1. 程式人生 > >談談對原型鏈的理解

談談對原型鏈的理解

許多OO語言支援兩種繼承方式:介面繼承和實現繼承。
介面繼承只繼承函式簽名,實現繼承則繼承實際的方法。
由於函式無簽名,在JavaScript中無法實現介面繼承。所以只能實現方法繼承。

實現繼承主要依賴原型鏈。
什麼是原型物件。我們知道每個建構函式一旦建立都有prototype指標指向它的原型物件(建構函式.prototype)。而原型物件(建構函式.prototype)會預設生成一個constructor指標又指向建構函式。在建立例項時,例項有一個內部屬性[[prototype]]指向該原型物件。原型物件內建立的所有方法會被所有例項共享。
來看段程式碼:

   function
Person{
}; Person.prototype.name = "Nichloas"; Person.prototype.age = 29; Person.prototype.job = "Software Enginner"; Person.prototype.sayName = function(){ alert(this.name); } var person1 = new Person(); person1.sayName(); //Nichloas var person2 = new Person(); person2.sayName(); //Nichloas

這裡寫圖片描述
這樣看著圖,再結合上面的原型物件的解釋就明白了。
還要說一點就是原型物件中的方法屬性是被所有例項共享的。如果含有引用型別的屬性,如陣列,修改person1中的陣列屬性,也會導致person2中的該屬性發生變化。

看一下什麼是原型鏈。

原型鏈就是建立一個建構函式,它會預設生成一個prototype屬性並指向原型物件。使用下一個建構函式的原型物件作為這個建構函式的例項。即 nextFuction.prototype = new thisFuction();
在下下一個建構函式的原型物件 = new nextFuction。這樣下去就會構成一條例項與原型之間的鏈條,這就是原型鏈。

function SuperType(){
this.property = true;
}

//在SuperType函式的原型鏈上建立公共方法
SuperType.prototype.getSuperValue = function(){
return this.property;
};

function SubType(){
this.subProperty = false;
}

//繼承了SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function(){
return this.subProperty;
}

var instance = new SubType();
alert(instance.getSuperValue()); //true;

函式之間的關係會是什麼樣子?
首先SuperType建構函式建立後會是這樣子的:
這裡寫圖片描述
SuperType函式本身內部會有一個prototype指標,指向SuperType Prototype(圖中還沒有畫出來)而在建構函式建立之後,會按照某種規則生成一個原型物件即SuperType.prototype,該原型物件中預設也會有一個指標constructor再指向建構函式。由於在原型鏈上我們添加了一個getSuperValue函式,所以會存在原型物件中。

SuperType建構函式中還有一個屬性property屬性,後面解釋。

然後建立了建構函式,再為其建立了屬性subProperty。又使其 原型物件成為SuperType建構函式的例項。我們知道例項中會自動生成一個[[prototype]]的內部屬性。所以就相當於該例項的預設方法重寫了SubType.prototype(原型物件)。
然後再定義新增屬性和方法到SubType.prototype中,最後SubType建構函式生成例項instance。
看最後的圖:
這裡寫圖片描述
現在來解釋一下為什麼property屬性沒有出現在SuperType的原型鏈中,而出現在了SubType的原型鏈中。subProperty沒有出現在SubType的原型鏈中,而出現在了instance例項中。
因為我們知道在建構函式中定義的屬性和方法實際上是例項的屬性和方法。即只能出現在例項中。而SubType.prototype是SuperType的例項,所以property屬性在其中。同理因為在建構函式SubType中定義的subProperty屬性是例項屬性,所以存在於instance中。例項中會有一個[[prototype]]內部屬性指向建構函式的原型物件。這樣就形成了一條鏈。
在通過原型鏈實現繼承的情況下,當讀取模式訪問例項中的屬性時,會先搜尋例項,然後再搜尋例項的原型,在一層一層知道找到或者到達原型鏈的末端停止。
其實我們上面的是少一環的,即Object。因為所有引用型別都是從object繼承來的。
這裡寫圖片描述
SubType繼承了SuperType,SuperType繼承了Object,當呼叫instance.toString方法,實際是呼叫了儲存在Object中的方法。