關於javascript 原型鏈維護和繼承詳解

一.兩個原型

關於javascript 原型鏈維護和繼承詳解

很多人都知道javascript是原型繼承,每個構造函數都有一個prototype成員,通過它就可以把javascript的繼承演義的美輪美奐了.

其實啊,光靠這一個屬性是無法完成javascript的繼承.

我們在代碼中使用的prototype完成繼承在這裏就不多說了.大家可以查一下資料.

另外一個看不見的prototype成員.

每一個實例都有有一條指向原型的prototype屬性,這個屬性是無法被訪問到的,當然也就無法被修改了,因爲這是維護javascript繼承的基礎.

複製代碼 代碼如下:

//構造器聲明

function Guoyansi(){ }

function GuoyansiEx(){}

//原型繼承

otype=new Guoyansi();

//創建對象

var g1=new GuoyansiEx();

var g2=new GuoyansiEx();

上面的代碼中的對象可以用下面的圖來說明

二.原型的維護

一個構造器產生的實例,其constructor屬性總是指向該構造器.我們暫且認爲該話是對的.

複製代碼 代碼如下:

function Guoyansi(){ }

var obj1=new Guoyansi();

(tructor===Guoyansi);//true

其實構造器本身是沒有constructor這個屬性的,那麼這個屬性是來自哪呢?

答案是:來自原型.

因此得出下面的結論

複製代碼 代碼如下:tructor===tructor===Guoyansi

既然我們可以通過constructor來尋找構造器.因此我們就可以進一步完善上面的圖了.

複製代碼 代碼如下:

function GuoyansiEx(){}

otype=new Guoyansi();

(tructor===GuoyansiEx)//false

根據上圖,上面的結果應該是true,但爲什麼是false呢?

現在做個分析.

GuoyansiEx的原型被Guoyansi的實例重寫了,那麼GuoyansiEx的原型中的constructor自然也是來自Guoyansi的實例.

而Guoyansi實例中的constructor又是來自otype.而otype沒有被重寫,

所以otype的constructor指向Guoyansi(構造函數);

根據以上分析得出下面的結論

複製代碼 代碼如下:tructor===tructor===Guoyansi;

如果在開發過程中對於Constructor的指向要求非常精確的.話,可以做如下處理.

複製代碼 代碼如下:

/**方法一:**/

function Guoyansi(){}

function GuoyansiEx(){}

otype=new Guoyansi();

tructor=GuoyansiEx;//重置constructor指向.

複製代碼 代碼如下:

/**

方法二

**/

function Guoyansi(){}

function GuoyansiEx(){

tructor=ee;

}

otype=new Guoyansi();

複製代碼 代碼如下:

/**

方法三

**/

function Guoyansi(){}

function GuoyansiEx(){

tructor=GuoyansiEx;

}

otype=new Guoyansi();

三.看不見的原型有什麼用呢?

看得見的原型鏈我們可以對他操作來完成我們的繼承,那麼這個看不見的原型鏈我們既看不見,又無法操作.要它有何用.

面向對象中繼承有一個特性:相似性.子類與父類具有相似性.因此在子類中你是無法用刪除從父類繼承而來的成員.也就是說子類必須具有父類的特性.

爲了維護這個特性,javascript在對象的內部產生了一條我們看不見的原型屬性,並且不允許用戶訪問.這樣,用戶可以處於任何目的來修改constructor,

而不會破壞子類擁有父類的特性.

簡而言之:內部原型是javascript的原型繼承機制所需要的,而外部原型是用戶實現繼承所需要的.

四.火狐引擎SpiderMonkey中的__proto__

還是這段代碼.

複製代碼 代碼如下:

function Guoyansi(){}

=24;

function GuoyansiEx(){}

var obj1=new Guoyansi();

otype=obj1;

tructor=GuoyansiEx;//重置constructor指向.

var obj2=new GuoyansiEx();

我現在想要從obj開始向上訪問父類Guoyansi的prototype的屬性的age.

思路是這樣的.

第一步:obj2====>otype

第二部:otype===>otype;

第三部:otype===>obj1;

第四部:tructor====>Guoyansi

第五部:

寫成這這樣:()//24;

最終的結果是24.

最終的結果是24.可以正常執行,但是在好多書上說constructor修改後,級無法在找到父類中的原型了.不知道是怎麼回事.

在火狐中提夠了一種更加簡潔的屬性._proto_

SpiderMonkey中默認在任何創建的對象上添加了一個名爲_proto_的屬性,該屬性指向構造器所用的原型.

其實就是我們上面提到的不可見的原型鏈,只不過是在這個地方變相的公開而已.

可以這樣訪問到age

(obj2.__proto__.__proto__);//24

這樣的確是成功的訪問到了父類的原型屬性,但是這個屬性只適用於火狐,在其他瀏覽器中是會出錯的.

在E5中對Object做出了擴展rototypeOf(),可以訪問到所有父類的原型了.

複製代碼 代碼如下:

function Guoyansi(){}

=24;

function GuoyansiEx(){}

var obj1=new Guoyansi();

otype=obj1;

tructor=GuoyansiEx;//重置constructor指向.

var obj2=new GuoyansiEx();

var proto=rototypeOf(obj2);

while(proto){

(tructor);

proto=rototypeOf(proto);

}

("object的原型"+proto);

結果是:GuoyansiEx

Guoyansi

Object

object的原型null

個人覺得這些應該算是javascript面向對象的精髓之一了.小夥伴們自己參考下,根據需求使用到自己的項目中去吧