組合式繼承的不足
組合繼承是JavaScript最常用的繼承模式赋荆,但也有它的不足:
- 無論什么情況下府框,都會調(diào)用兩次超類構(gòu)造函數(shù)
- 子類會包含超類對象全部的實(shí)例屬性,但又不得不在調(diào)用子類構(gòu)造函數(shù)時(shí)重寫這些屬性
先看一看組合繼承的例子:
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name); // 第二次調(diào)用 SuperType()
this.age = age;
}
SubType.prototype = new SuperType(); // 第一次調(diào)用 SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
如代碼所示,
- 在第一次調(diào)用 SuperType 構(gòu)造函數(shù)SubType.prototype 會得到兩個(gè)屬性: name 和 colors ;它們都是 SuperType 的實(shí)例屬性,只不過
現(xiàn)在位于 SubType 的原型中罩驻。- 當(dāng)調(diào)用 SubType 構(gòu)造函數(shù)時(shí)穗酥,又會調(diào)用一次 SuperType 構(gòu)造函數(shù),這一次又在新對象上創(chuàng)建了實(shí)例屬性 name 和 colors 惠遏。于是砾跃,這兩個(gè)屬性就屏蔽了原型中的兩個(gè)同名屬性
解決方案
有兩組 name 和 colors 屬性:一組在實(shí)例上,一組在 SubType 原型中节吮,這是不合理的抽高。解決這個(gè)問題方法是:寄生組合式繼承。
寄生組合式繼承基本模式:
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //創(chuàng)建對象
prototype.constructor = subType; //增強(qiáng)對象
subType.prototype = prototype; //指定對象
}
這個(gè)函數(shù)接收兩個(gè)參數(shù):子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù), 執(zhí)行以下步驟:
- 第一步是創(chuàng)建超類型原型的一個(gè)副本透绩。
- 為創(chuàng)建的副本添加 constructor 屬性翘骂,從而彌補(bǔ)因重寫原型而失去的默認(rèn)的 constructor 屬性。
- 將新創(chuàng)建的對象(即副本)賦值給子類型的原型帚豪。
現(xiàn)在我們就可以用調(diào)用 inheritPrototype() 函數(shù)的語句碳竟,去替換前面例子中為子類型原型賦值的語句了,修改后的代碼如下:
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
};
這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次 SuperType 構(gòu)造函數(shù)狸臣,并且因此避免了在 SubType.prototype 上面創(chuàng)建不必要的莹桅、多余的屬性。與此同時(shí)烛亦,原型鏈還能保持不變诈泼;因此,還能夠正常使用instanceof 和 isPrototypeOf() 煤禽。普遍認(rèn)為寄生組合式繼承是引用類型最理想的繼承范式铐达。