先說說組合繼承。最經常使用的繼承方式組合繼承,其最大的問題是不管在什麼狀況下,都會調用兩次超類型的構造函數:一次是在建立子類原型的時候,另外一次是在子類型構造函數內部。javascript
組合繼承是經過原型繼承方法和原型屬性,構造函數繼承實例屬性。但子類經過原型也繼承了超類型的所有實例屬性(方法暫且不說),即超類的實例屬性成爲子類的原型屬性,因此不得不在調用子類構造函數時重寫這些屬性。也就是說在子類的原型對象上繼承來自超類的實例屬性徹底是多餘的。java
看一個組合繼承的例子。函數
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); }; var instance = new SubType('Greg',39); //調用SubType構造函數,重寫原型屬性 instance.colors.push('black'); //重寫原型屬性
在第一次調用SuperType構造函數時,SubType.prototype獲得兩個屬性,name和colors(這兩個經過原型繼承來的屬性是多餘的)。當建立instance實例調用SubType的構造函數時會再一次調用SuperType的構造函數,這一次又在新對象上建立了實例屬性name和colors,也就是重寫了原型對象的屬性,屏蔽了原型中兩個同名屬性。this
爲了不這種兩次調用超類構造函數致使子類原型對象建立了多餘屬性的缺陷,可使用寄生組合式繼承。spa
什麼是寄生組合式繼承?即經過借用構造函數來繼承屬性,經過原型鏈的混成方式來繼承方法。prototype
基本思路是:沒必要爲了指定子類型的原型而調用構造函數,咱們所須要的無非是超類型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,而後將結果指定給子類型的原型。code
基本模式以下:orm
仍是要用以前的 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屬性,使其指向subType,彌補由於重寫原型而失去默認的constructor屬性。最後一步,將副本賦值給子類型的原型。整個過程說的簡單點,就是將超類原型對象的一個副本複製給子類的原型對象。這樣一來就能夠避免繼承超類的實例屬性,也就是避免了在子類原型對象上建立多餘的屬性了。再舉一個例子。
function superType(name){ this.name = namel this.colors = ['red','blue','yellow']; } 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()。寄生式組合繼承是引用類型最理想的繼承範式。