回顧一下構造函數、原型和實例的關係:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。(將一個類型的實例賦值給另外一個構造函數的原型時,就通過原型鏈來實現了繼承。那麼子類就能夠訪問到超類的全部方法和屬性,包括原型方法和屬性。)
通過原型鏈實現繼承時,不能夠使用對象字面量創建原型方法,因爲這樣會重寫原型鏈。
實例共享所有繼承的屬性和方法,因此不適宜單獨使用。解決方法是借用構造函數,即在子類型構造函數的內部調用超類型構造函數。這樣就可以做到每個實例都具有自己的屬性,同時還能保證只使用構造函數模式來定義類型。
使用最多的就是組合繼承模式,這種模式使用原型鏈繼承共享的屬性和方法,而同通過借用構造函數來繼承實例屬性。開發人員普遍認爲寄生組合模式繼承是最理想的繼承模式。
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(){
alert(this.name);
}
function subType(name,age){
SuperType.call(this,name); -//借用構造函數來繼承實例屬性
this.age=age;
}
inheritPrototype(Subtype,Supertype);
Subtype.prototype.sayAge=function(){
alert(this.age);
}
上面例子的高效率體現在它只調用一次的Supertype構造函數,並且因此避免了在SubType.prototype上面創建不必要的,多餘的屬性。以此同時,原型鏈還能夠保持不變;因此,還能夠正常使用instanceof 和isPrototypeOf()。