有继承,必定会有两个构造函数,一个是父类,一个是子类,只有这样才能发生继承关系。话不多说直接进入主题。
这里先声明一个父类Person
, 下面的继承均继承于这里的Person
父类。
function Person(name){
this.name = name || 'person'
this.eat = function(){
console.log('this is eat');
}
}
Person.prototype.sayHi = function(){
console.log('this is sayHi');
}
1. 原型继承
依据每个对象都有一个__proto__
属性, 所有继承的都通过原型链来查找
当new Person
会打印出
{
name: 'person',
eat: function () {},
__proto__: {
constructor: Person,
sayHi: function () {},
__proto__: Object
}
}
当我们新创建一个构造函数Student
时
function Student(){
}
Student.prototype = new Person
var s = new Student
打印结果为
{
__proto__: {
name: 'Person',
eat: function(){}
__proto__:{
constructor: Person,
sayHi: function () {},
__proto__: Object
}
}
}
3. 借用构造函数继承
主要是通过call
方法来改变this
指向实现的。
function Student(name) {
// 在这里执行 Person 这个函数内部的所有代码
// 并且吧代码中的 this 改变成 指向 s
Person.call(this)
}
var s = new Student
console.log(s);
缺陷: 没有继承父类的原型的属性和方法
打印出结果为:
{
name: 'person',
eat: function () {},
__proto__: {
constructor: Student,
__proto__: Object
}
}
3. 组合继承
是将原型继承和借用构造函数继承相结合的方法。
这样会重复父类的私有属性
function Student (){
Person.call(this)
}
Student.prototype = new Person
var s = new Student
打印结果为
{
name: 'person',
eat: function () {},
__proto__: {
name: 'person',
eat: function () {},
__proto__: {
constructor: Person,
sayHi: function () {},
__proto__: Object
}
}
}
4. 拷贝继承
主要使用了for in
遍历式的对象,
使用方法:
在构造函数中使用new Person
把父类遍历到构造函数的原型中
function Student(){
var p = new Person
for(var key in p){
Student.prototype[key] = p[key]
}
}
var s = Student
结果为
{
__proto__: {
constructor: Student,
name: 'person',
eat: function () {},
sayHi: function () {},
__proto__: Object
}
}
for in 对性能的消耗比较高
5. 寄生式继承
主要使用了return
方法, 结束函数执行并返回函数结果
使用: return一个new Person
function Student(){
this.abc = "abc"
var p = new Person
return p
}
Student.prototype.fn = function(){}
var s = new Student
打印结果为
{
__proto__:{
name: 'person',
eat: function (){}
__proto__:{
constructor: Person,
say: function(){}
__proto__: Object
}
}
}
这样自己的私有属性和原型都没有了
6. 寄生式继承1
主要使用了借用构造函数继承和寄生式继承
function Student(){
Person.call(this) // 不能继承父类的原型
}
Student.prototype = Person.prototype
Student.prototype.fn = function(){}
var s = new Student
结果为
{
name: 'person',
eat: function () {},
__proto__: {
constructor: Person,
sayHi: function () {},
__proto__: Object
}
}
这样看似是操作的Student,实际上是操作的父类,这里添加的fn方法,父类中也会出现
7. 寄生式继承2
主要使用了组合 构造函数和寄生式继承
function Student(name) {
Person.call(this) // 没有继承父类的原型属性和方法
}
// Abc 没有私有属性
(function () {
function Abc() {
// this.constructor = Student
}
Abc.prototype = Person.prototype
Student.prototype = new Abc
})()
Student.prototype.constructor = Student
Student.prototype.fn = function () {}
var s = new Student
缺陷
书写复杂
当我不需要操作 自己的 prototype 的时候,多出来的那一个东西
就是在我们的原型链上多加了一个环节
属性或者方法获取的时候,原型链查找机制会多消耗了一次性能
8. 淼式继承法
在借用构造函数的基础上
使用拷贝继承,但是拷贝的不是 new Person,而是直接拷贝 Perosn.prototype
function Student(name) {
Person.call(this)
}
/*
自执行函数
()()
!function () {}
~function () {}
*/
~function () {
var obj = Person.prototype
for (var key in obj) {
Student.prototype[key] = obj[key]
}
}
Student.prototype.fn = function () {}
var s = new Student
但是使用了for in循环,会增加性能消耗