JS繼承之原型繼承


 許多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的一些重要的基礎知識點,秋招秋招。。。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM