寄生组合式继承
前面说过,组合继承是JavaScript最常用的继承模式。
不过,它也有自己的不足之处。组合继承最大的问题在于无论什么情况下,都会调用两次超类型的构造函数。
- 一次是创建子类型原型的时候
function Person() {
this.name = '天下';
this.colors = ['red','yellow','blue'];
}
Son.prototype = new Person();
- 一次是子类型构造函数中
function Son() {
Person.call(this);
}
没错,子类型最终包含超类型对象的全部实例属性,但我们不得不在调用子类型构造函数时重写这些属性。
function Person21(name) {
this.name = name;
this.colors = ['red','blue','yellow'];
}
Person21.prototype.sayName = function() {
console.log('Person21-this.name',this.name);
}
function Son21(name,age) {
//继承了属性
Person21.call(this,name);
this.age = age;
}
//继承方法
//重写原型
Son21.prototype = new Person21();
console.log('Son21.prototype.constructor',Son21.prototype.constructor); //Person21
Son21.prototype.constructor = Son21;
console.log('Son21.prototype.constructor123',Son21.prototype.constructor); //Son21
var son21 = new Son21('天下666',18);
console.log('son21',son21);
son21.colors.push('black');
console.log('son21.colors',son21.colors);
son21.sayName();
//属性是私有的,方法是共享的
var son211 = new Son21('晓666',22);
console.log('son211.colors',son211.colors);
son211.sayName();
上面代码中为何有这么一行代码呢?
Son21.prototype.constructor = Son21;
因为上文执行Son21.prototype = new Person21()
这行代码之后,它的Son21.prototype.constructor
就指向了Person21。因此在这里需要指定到Son21上。
寄生组合式继承
所谓寄生式组合继承,即通过借用构造函数来继续属性,通过原型链的混成形式继承方法。
其背后的思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们需要的无非就是超类型的一个副本而已。
本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function inheritPrototype(Son24,Person24) {
//复制一个Person24原型的副本
var proto = Object(Person24.prototype);
//proto.constructor 指向Person24
console.log('proto.constructor',proto.constructor); //Person24
//如果不指定这一步会如何?
proto.constructor = Son24;
Son24.prototype = proto;
}
function Person24(name) {
this.name = name;
this.colors = ['red','yellow','blue'];
}
Person24.prototype.sayName = function() {
return this.name;
}
function Son24(name,age) {
Person24.call(this,name);
this.age = age;
}
inheritPrototype(Son24,Person24);
var son24 = new Son24('tianxia',666);
son24.colors.push('haha');
console.log('son24',son24);
var son241 = new Son24('xiaoxiao',123);
son241.colors.push('dd');
console.log('son241',son241);
//方法是共享的
console.log('son24.sayName',son24.sayName());
console.log('son241.sayName',son241.sayName());