談談對原型鏈的理解

許多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中的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章