1. 程式人生 > >面向物件(繼承)--寄生組合式繼承06

面向物件(繼承)--寄生組合式繼承06

還記得組合繼承嗎,回憶一下

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); // 第二次呼叫 SuperType()
    this.age = age;
}
SubType.prototype = new SuperType(); // 第一次呼叫 SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
    alert(this.age);
};

在第一次呼叫 SuperType 建構函式:SubType.prototype 會得到兩個屬性: name 和 colors ;它們都是 SuperType 的例項屬性,只不過現在位於 SubType 的原型中。

在第二次呼叫 SuperType 建構函式:當呼叫 SubType 建構函式時,就會呼叫 SuperType 建構函式。在新物件上建立了例項屬性 name 和 colors 。這兩個屬性就遮蔽了原型中的兩個同名屬性。

問題就出在有兩組 name 和 colors 屬性:一組在例項上,一組在 SubType 原型中,請看下圖就會一目瞭然

 使用寄生組合式繼承可以解決這個問題,寄生組合式繼承的本質是使用寄生式繼承來繼承超型別的原型,然後再將結果指定給子型別的原型。

先回憶一下object()函式

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; //指定物件
}

在函式內部,第一步是建立超型別原型的一個副本。第二步是為建立的副本新增 constructor 屬性,從而彌補因重寫原型而失去的預設的 constructor 屬性。最後一步,將新建立的物件(即副本)賦值給子型別的原型。

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 上面建立不必要的、多餘的屬性。與此同時,原型鏈還能保持不變;