許多OO語言都支持兩種繼承方式:介面繼承和實現繼承。介面繼承只繼承方法簽名,而實現繼承則繼承實際的方法。如前所述,由於函數沒有簽名,在ECMAScript中無法實現介面繼承。ECMAScript只支持實現繼承,而且其實現繼承主要是依靠原型鏈來實現的。 --摘自《JavaScript高級程式設計》 - ...
許多OO語言都支持兩種繼承方式:介面繼承和實現繼承。介面繼承只繼承方法簽名,而實現繼承則繼承實際的方法。如前所述,由於函數沒有簽名,在ECMAScript中無法實現介面繼承。ECMAScript只支持實現繼承,而且其實現繼承主要是依靠原型鏈來實現的。 --摘自《JavaScript高級程式設計》
function SuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function(){ return this.property; } function SubType(){ this.subproperty=false; } SubType.prototype=new SuperType();
SubType.prototype.getSubValue=function(){
return this.property;
}
var instance=new SubType();
instance.getSuperValue(); //true;
例子中的實例及構造函數和原型之間的關係圖:
在例子代碼中,定義了兩個對象,subType和superType。
兩個對象之間實現了繼承,而這種繼承方式是通過創建SuperType的實例並將該實例賦給subType.prototype實現的。實現的本質就是重寫了原型對象。
這樣subType.prototype中就會存在一個指針指向superType的原型對象。也就是說,存在superType的實例中的屬性和方法現在都存在於subType.prototype中了。這樣繼承了之後,又可以為subType添加新的方法和屬性。
要註意,這個指針([[prototype]])預設情況下是不可以再被外部訪問的,估計是會被一些內部方法使用的,例如用for...in來遍歷原型鏈上可以被枚舉的屬性的時候,就需要通過這個指針找到當前對象所繼承的對象。不過,Firefox、Safari和Chrome在每個對象上都支持一個屬性__proto__。
原型繼承需要註意的一些問題
1.別忘記預設的類型
我們知道,所有的引用類型都繼承了Object,而這個繼承也是通過原型鏈實現的。所以所有的對象都擁有Object具有的一些預設的方法。如:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()和valueOf()。
2. 確定原型和實例的關係
可以通過兩種方式來確定原型和實例之間的關係。
①使用instanceof 操作符,只要用這個操作符來測試實例與原型鏈中出現過的構造函數,結果就會返回true。
②第二種方式是使用isPrototypeOf()方法。同樣,只要是原型鏈中出現過的原型,都可以說是該原型鏈所派生的實例的原型,因此isPrototypeOf()方法也會返回true。
例子:
alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(SubType.prototype.isPrototypeOf(instance)); //true
③子類要在繼承後定義新方法
因為,原型繼承是實質上是重寫原型對象。所以,如果在繼承前就在子類的prototype上定義一些方法和屬性。那麼繼承的時候,子類的這些屬性和方法將會被覆蓋。
如圖:
④不能使用對象字面量創建原型方法
這個的原理跟第三點的實際上是一樣的。當你使用對象字面量創建原型方法重寫原型的時候,實質上相當於重寫了原型鏈,所以原來的原型鏈就被切斷了。
⑤註意父類包含引用類型的情況
如圖:
這個例子中的SuperType 構造函數定義了一個colors 屬性,該屬性包含一個數組(引用類型值)。SuperType 的每個實例都會有各自包含自己數組的colors 屬性。當SubType 通過原型鏈繼承了SuperType 之後,SubType.prototype 就變成了SuperType 的一個實例,因此它也擁有了一個它自己的colors 屬性——就跟專門創建了一個SubType.prototype.colors 屬性一樣。但結果是什麼呢?結果是SubType 的所有實例都會共用這一個colors 屬性。而我們對instance1.colors 的修改能夠通過instance2.colors 反映出來。也就是說,這樣的修改會影響各個實例。
原型繼承的缺點(問題)
①最明顯的就是上述第⑤點,有引用類型的時候,各個實例對該引用的操作會影響其他實例。
②沒有辦法在不影響所有對象實例的情況下,給超類型的構造函數傳遞參數。
有鑒於此,實踐中很少會單獨使用原型繼承。
最近要回顧一下原生js的一些重要的基礎知識點,秋招秋招。。。