《JS高级程序设计》第6章的读书笔记
- 创建对象(一)工场模式和构造函数模式
- 创建对象(二)原型模式和组合模式
- 创建对象(三)再探原型
- 对象继承(一)原型链
- 对象继承 (二)借用构造函数和组合继承
- 对象继承(三)原型式继承和寄生式继承
- 对象继承(四)寄生组合式继承
1 组合式继承的问题
组合继承是JS最常用的继承模式,但是它也有问题,(OS:还有完没完了),就是无论在什么情况下,都会调用两次超类型构造函数。具体如何,请看代码:
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name); //第二次调用
this.age = age;
}
SubType.prototype = new SuperType();//第一次调用
SubType.prototype.constructor = SubType();
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var instance = new SubType('achao', 22);
我们可以看到:第一次调用超类型构造函数,是在重写子类型原型的时候,也就是开始继承的时候,第二次是创建子类型实例时,调用子类型构造函数内部调用了超类型构造函数。
第一次调用超类型构造函数时,SubType.prototype会得到两个属性,colors和name,虽然name的值是undefined
第二次调用超类型构造函数时,也就是创建实例时,子类型实例上会得到colors和name两个属性,覆盖原型对象的同名属性。
具体见下图:
创建实例前
创建实例后
为了提高继承的性能,减少继承的开销。开发者相出了新的继承方式:寄生组合式继承。
2 寄生组合式继承
下面的代码是寄生组合式继承的基本模式。
寄生组合式继承可以说是组合继承的2.0增强版
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); // 创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
该函数要求传入子类型构造函数和超类型构造函数。
在函数内部,第一步是创建一个父类型原型的副本,第二部是为添加的副本重写construtor属性,指向子类型。最后一步,将得到的原型指定为子类型的原型。
这里没有调用超类型构造函数哦。
这段函数用以替代组合模式的关键继承语句:
SubType.prototype = new SuperType();
所以寄生组合式继承最终的代码是这样的:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); // 创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
//SubType.prototype = new SuperType();
inheritPrototype(SubType, SuperType);
SubType.prototype.constructor = SubType();
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var instance = new SubType('achao', 22);
寄生组合式继承只调用了一次超类型构造函数,从而避免在子类型原型上创建多余不必要的属性;还能正确使用instanceof和isPrototypeOf。这种继承方式被认为是最理想的继承方式,虽然使用频率不如组合继承。
下图很很好地描述寄生组合式继承:
寄生组合式继承正确使用instanceof和isPrototypeOf的例子:
console.log(instance instanceof SubType); //true
console.log(instance instanceof SuperType); //true
console.log(SubType.prototype.isPrototypeOf(instance)); //true
console.log(SuperType.prototype.isPrototypeOf(instance)); //true