常见继承方式分为以下几种:
1. 构造函数继承
// 构造函数继承
function Parent1(){
this.name = 'bob'
this.key = 'key'
}
Parent1.prototype.say = function(){
console.log('hello')
}
function Child1(){
Parent1.call(this) //改变this指向
this.age = 12
}
let s1 = new Child1()
console.log(s1.name) // 'bob'
console.log(s1.say) // undefined
实现了基础继承, 缺点显而易见,实例无法获得父类原型上的方法和属性.
2. 原型链继承
// 原型链继承 多个实例共享父级属性
function Parent2(){
this.name = 'bob2';
this.arr = [1, 2, 4]
}
function Child2(){
this.age = 10
}
Child2.prototype = new Parent2();
let s2 = new Child2();
let s3 = new Child2();
s2.arr.push(9)
console.log(s2.arr) // [1,2,4,9]
console.log(s3.arr) // [1,2,4,9]
实现了继承, 子类也可以继承父类原型上的方法和属性.
缺点显而易见:
1.多个实例共享父类属性,不存在私有属性,
2.当父类上存在引用类型的数据时,实例可以通过方法更改数据并且在更改完成以后,影响其他实例.
3. 组合继承
// 结合 构造函数继承-原型链继承的优点
function Parent3(){
this.name = 'bob2';
this.arr = [1, 2, 4]
}
Parent3.prototype.say = function(){
console.log('111')
}
function Child3(){
Parent3.call(this) // 第一次调用父类
this.age = 10
}
Child3.prototype = new Parent3; //第二次调用父类
let s3 = new Child3;
let s4 = new Child3;
s3.arr.push(7);
console.log(s3.arr) // [1,2,4,7]
console.log(s4.arr) // [1,2,4]
组合继承实现了继承,也完成了继承父类属性私有化,实例之间互不影响.
缺点是: 调用了二次父类,性能开销较大.
4. 组合继承-优化1
// 将二次调用父类变成一次
function Parent4(){
this.name = 'bob2';
this.arr = [1, 2, 4]
}
Parent4.prototype.say = function(){
console.log('111')
}
function Child4(){
Parent4.call(this) // 第一次调用父类
this.age = 10
}
Child4.prototype = Parent4.prototype; // 子类原型指向父类原型
let s5 = new Child4;
let s6 = new Child4;
s5.arr.push(7);
console.log(s5.arr) // [1,2,4,7]
console.log(s6.arr) // [1,2,4]
console.log(s5.constructor) // Parent4
console.log(s5 instanceof Parent4) // true
console.log(s5 instanceof Child4) // true
优化了二次调用,利用原型链完成了继承.
缺点是: 因为改变了原型指向,导致实例对象的原型指向了父类.
5. 组合继承-优化2(常用)
// 利用ES5的Object.creat()方法
function Parent5(){
this.name = 'bob2';
this.arr = [1, 2, 4]
}
Parent5.prototype.say = function(){
console.log('111')
}
function Child5(){
Parent4.call(this) // 第一次调用父类
this.age = 10
}
Child5.prototype = Object.create(Parent5.prototype)
Child5.prototype.constructor = Child5 // 修改子类原型的构造函数指向自身
let s5 = new Child5;
let s6 = new Child5;
s5.arr.push(7);
console.log(s5.arr) // [1,2,4,7]
console.log(s6.arr) // [1,2,4]
console.log(s5.constructor) // 指向子类Child5
console.log(s5 instanceof Parent4) // true
console.log(s5 instanceof Child4) // true