JavaScript中原型鏈的那些事

2021-08-22 13:38:46 字數 4129 閱讀 8977

在物件導向的語言中繼承是非常重要的概念,許多物件導向語言都支援兩種繼承方式:介面繼承和實現繼承。介面繼承制只繼承方法簽名,而實現繼承繼承實際的方法。在ecmascript中函式沒有簽名,所以ecmascript無法實現介面繼承,只能實現實現繼承。那麼是怎麼實現實現繼承的呢??這就要說一說js中的原型鏈了。

什麼是原型鏈?這個問題很簡單,其基本思想就是利用原型讓乙個引用型別繼承另乙個引用型別的屬性和方法。

我們先來回顧一下建構函式,原型,例項之間的關係。每乙個建構函式都有乙個原型物件,原型物件中包含乙個指向建構函式的指標,而例項都包含乙個指向原型物件的內部指標。在原型物件中通過prototype指向建構函式,而在例項中通過__proto__指向原型物件,但是該屬性是區分瀏覽器的,這是部分瀏覽器為例項物件新增的屬性,在ecmascript中表現為[[prototype]]。

現在我們已經知道了原型物件中存在乙個指標指向建構函式,現在我們讓原型物件等於另乙個型別的例項,此時的原型物件將包含乙個指向另乙個原型的指標,那麼另乙個原型中也包含乙個指向另乙個建構函式的指標。加入另乙個原型有事另乙個型別的例項,那麼如此層層遞進,就構成了例項與原型的鏈條。這就是原型鏈的基本概念。

我的理解

function supertype() 

super.prototype.getsupervalue = function()

function subtype()

subtype.prototype = new supertype();

subtype.prototype.getsubvalue = function()

var instance = new subtype();

console.log(instance.getsupervalue());

//輸出:true

可以看出來,在上述**中,原型鏈的繼承是通過建立supertype的例項並將例項賦給subtype的原型實現的。本質就是重寫原型物件,換成乙個新型別的例項。原來存在於supertype的例項中的所有屬性和方法都會存在於subtype.prototype中。最終結果是這樣的:instance指向subtype的原型,subtype的原型又指向supertype的原型。

有一點需要注意的是,instance.constructor現在指向的不是subtype,而是supertype,原因是subtype的原型指向了另外乙個物件supertype的原型,而這個原型物件的constructor屬性指向的是supertype。

在學習原型鏈的時候經常搞不懂prototype和__proto__的區別,所以把這兩個東西的比較摘出來寫成一塊。

__proto__屬性的來歷:建立了自定義的建構函式後其原型物件只會取得constructor屬性,其他的方法都是從object繼承的,當使用建構函式的建立乙個新的例項的時候該例項內部包含乙個指標指向建構函式的原型物件。在ecmascript中管這個指標叫做[[prototype]]。在指令碼中沒有標準的方式訪問這個指標。但firefox、safari、chrome在每個物件上都支援乙個屬性__proto__;但是在其他的實現中,這個屬性對指令碼是完全不可見的。

所有引用型別預設繼承object,而這個繼承也是通過原型鏈實現的。所有函式的預設原型都是object的例項,所以在預設原型都會包含乙個內部指標,指向object.prototype。這也是自定義型別都會竭誠tostring()、valueof()等預設方法的原因

1. 給原型新增方法的**一定要放在替換原型的語句之後。

如下例:

function supertype() 

supertype.prototype.getsupervalue = function()

function subtype()

subtype.prototype = new supertype();

//新增新方法

subtype.prototype.getsubvalue = function()

//重寫超型別中的方法

subtype.prototype.getsupervalue = function()

var instance = new subtype();

console.log(instance.getsupervalue());

//輸出:false

在上面**中,重寫的方法會遮蔽原來的方法。當通過subtype的例項呼叫getsupervalue()時,呼叫的就是重新定義的方法,但通過supertype的例項呼叫getsupervalue()時,還會呼叫原來的方法。

2. 在通過原型鏈實現繼承的時候,不能使用物件字面量建立原型方法。

這樣會重寫原型鏈。如下例所示:

function supertype() 

supertype.prototype.getsupervalue = function()

function subtype()

subtype.prototype = new supertype();

subtype.prototype = ,

someothermethod: function()

}var instace = new subtype();

console.log(instace.getsupervalue());

輸出:

在上面的例子中,我們把supertype的例項賦值給原型,緊接著有獎原型替換成乙個物件字面量,由於現在的原型包含的是乙個object例項,而非supertype的例項,一次原型鏈已經被切斷,supertype和subtype已經沒有關係了。

1.我們都只知道引用型別的物件中儲存的是指向堆記憶體的指標,所以包含引用型別值的原型屬性會被所有例項共享。因為在原型物件中的引用型別只是乙個指標,在例項化物件的時候,指標複製,但是指標指向沒有發生變化。這也是為什麼要在建構函式中,而不是在原型物件中定義屬性的原因了。看下面的**:

function supertype() 

function subtype()

subtype.prototype = new supertype();

var instace1 = new subtype();

instace1.colors.push('black');

console.log(instace1.colors);

var instace2 = new subtype();

console.log(instace2.colors);

//輸出:

// ["red", "blue", "green", "black"]

// ["red", "blue", "green", "black"]

需要注意的是,在js中基本型別值的原型屬性並不是這樣的:

function supertype() 

function subtype()

subtype.prototype = new supertype();

var instace1 = new subtype();

instace1.property = false;

console.log(instace1.property);

var instace2 = new subtype();

console.log(instace2.property);

//輸出:

// false

// true

原因相比通過上面的例項大家都知道了,在js中基本型別值的儲存並不是通過指標。

2.在建立子型別的例項時,不能向超型別的建構函式中傳遞引數。

以上~~

JavaScript中原型和原型鏈

原型 prototype 為其他物件提供共享屬性的物件。每個函式都有乙個原型 prototype 屬性,這個屬性是乙個指標,指向乙個物件,這個物件包含特定例項共享的一些屬性和方法。以例服人 這個例子說明了原型物件是共享的,並且是乙個指標,並且物件的例項中也有指向prototype指向物件的指標。fu...

JavaScript中原型鏈存在的問題解析

本文通過例項給大家介紹js原型鏈存在的問題解析,非常不錯,具有參考借鑑價值,感興趣的朋友一起看看吧 我們知道使用原型鏈實現繼承是乙個goodway 看個原型鏈繼承的例子。1 2 3 4 5 6 7 8 9 10 11 functiona a.prototype.getabc function fun...

js中原型和原型鏈

let hd new object object.prototype.show function function getname console.dir getname console.log getname.prototype.proto getname.proto proto true con...