javascript 原型鏈維護(hù)和繼承詳解
一.兩個(gè)原型
很多人都知道javascript是原型繼承,每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype成員,通過(guò)它就可以把javascript的繼承演義的美輪美奐了.
其實(shí)啊,光靠這一個(gè)屬性是無(wú)法完成javascript的繼承.
我們?cè)诖a中使用的prototype完成繼承在這里就不多說(shuō)了.大家可以查一下資料.
另外一個(gè)看不見(jiàn)的prototype成員.
每一個(gè)實(shí)例都有有一條指向原型的prototype屬性,這個(gè)屬性是無(wú)法被訪問(wèn)到的,當(dāng)然也就無(wú)法被修改了,因?yàn)檫@是維護(hù)javascript繼承的基礎(chǔ).
//構(gòu)造器聲明
function Guoyansi(){ }
function GuoyansiEx(){}
//原型繼承
GuoyansiEx.prototype=new Guoyansi();
//創(chuàng)建對(duì)象
var g1=new GuoyansiEx();
var g2=new GuoyansiEx();
上面的代碼中的對(duì)象可以用下面的圖來(lái)說(shuō)明
二.原型的維護(hù)
一個(gè)構(gòu)造器產(chǎn)生的實(shí)例,其constructor屬性總是指向該構(gòu)造器.我們暫且認(rèn)為該話是對(duì)的.
function Guoyansi(){ }
var obj1=new Guoyansi();
console.log(obj1.constructor===Guoyansi);//true
其實(shí)構(gòu)造器本身是沒(méi)有constructor這個(gè)屬性的,那么這個(gè)屬性是來(lái)自哪呢?
答案是:來(lái)自原型.
因此得出下面的結(jié)論
既然我們可以通過(guò)constructor來(lái)尋找構(gòu)造器.因此我們就可以進(jìn)一步完善上面的圖了.
function GuoyansiEx(){}
GuoyansiEx.prototype=new Guoyansi();
console.log(GuoyansiEx.constructor===GuoyansiEx)//false
根據(jù)上圖,上面的結(jié)果應(yīng)該是true,但為什么是false呢?
現(xiàn)在做個(gè)分析.
GuoyansiEx的原型被Guoyansi的實(shí)例重寫(xiě)了,那么GuoyansiEx的原型中的constructor自然也是來(lái)自Guoyansi的實(shí)例.
而Guoyansi實(shí)例中的constructor又是來(lái)自Guoyansi.prototype.而Guoyansi.prototype沒(méi)有被重寫(xiě),
所以Guoyansi.prototype的constructor指向Guoyansi(構(gòu)造函數(shù));
根據(jù)以上分析得出下面的結(jié)論
如果在開(kāi)發(fā)過(guò)程中對(duì)于Constructor的指向要求非常精確的話,可以做如下處理.
/**方法一:**/
function Guoyansi(){}
function GuoyansiEx(){}
GuoyansiEx.prototype=new Guoyansi();
GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
/**
方法二
**/
function Guoyansi(){}
function GuoyansiEx(){
this.constructor=arguments.callee;
}
GuoyansiEx.prototype=new Guoyansi();
/**
方法三
**/
function Guoyansi(){}
function GuoyansiEx(){
this.constructor=GuoyansiEx;
}
GuoyansiEx.prototype=new Guoyansi();
三.看不見(jiàn)的原型有什么用呢?
看得見(jiàn)的原型鏈我們可以對(duì)他操作來(lái)完成我們的繼承,那么這個(gè)看不見(jiàn)的原型鏈我們既看不見(jiàn),又無(wú)法操作.要它有何用.
面向?qū)ο笾欣^承有一個(gè)特性:相似性.子類與父類具有相似性.因此在子類中你是無(wú)法用delete刪除從父類繼承而來(lái)的成員.也就是說(shuō)子類必須具有父類的特性.
為了維護(hù)這個(gè)特性,javascript在對(duì)象的內(nèi)部產(chǎn)生了一條我們看不見(jiàn)的原型屬性,并且不允許用戶訪問(wèn).這樣,用戶可以處于任何目的來(lái)修改constructor,
而不會(huì)破壞子類擁有父類的特性.
簡(jiǎn)而言之:內(nèi)部原型是javascript的原型繼承機(jī)制所需要的,而外部原型是用戶實(shí)現(xiàn)繼承所需要的.
四.火狐引擎SpiderMonkey中的__proto__
還是這段代碼.
function Guoyansi(){}
Guoyansi.prototype.age=24;
function GuoyansiEx(){}
var obj1=new Guoyansi();
GuoyansiEx.prototype=obj1;
GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
var obj2=new GuoyansiEx();
我現(xiàn)在想要從obj開(kāi)始向上訪問(wèn)父類Guoyansi的prototype的屬性的age.
思路是這樣的.
第一步:obj2====>obj2.constructor.prototype
第二部:obj2.constructor.prototype===>GuoyansiEx.prototype;
第三部:GuoyansiEx.prototype===>obj1;
第四部:obj1.constructor====>Guoyansi
第五部:Guoyansi.prototype.age
寫(xiě)成這這樣:console.log(obj2.constructor.prototype.constructor.prototype.age)//24;
最終的結(jié)果是24.
最終的結(jié)果是24.可以正常執(zhí)行,但是在好多書(shū)上說(shuō)constructor修改后,級(jí)無(wú)法在找到父類中的原型了.不知道是怎么回事.
在火狐中提夠了一種更加簡(jiǎn)潔的屬性._proto_
SpiderMonkey中默認(rèn)在任何創(chuàng)建的對(duì)象上添加了一個(gè)名為_(kāi)proto_的屬性,該屬性指向構(gòu)造器所用的原型.
其實(shí)就是我們上面提到的不可見(jiàn)的原型鏈,只不過(guò)是在這個(gè)地方變相的公開(kāi)而已.
可以這樣訪問(wèn)到age
console.log(obj2.__proto__.__proto__.age);//24
這樣的確是成功的訪問(wèn)到了父類的原型屬性,但是這個(gè)屬性只適用于火狐,在其他瀏覽器中是會(huì)出錯(cuò)的.
在E5中對(duì)Object做出了擴(kuò)展Object.getPrototypeOf(),可以訪問(wèn)到所有父類的原型了.
function Guoyansi(){}
Guoyansi.prototype.age=24;
function GuoyansiEx(){}
var obj1=new Guoyansi();
GuoyansiEx.prototype=obj1;
GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
var obj2=new GuoyansiEx();
var proto=Object.getPrototypeOf(obj2);
while(proto){
console.log(proto.constructor);
proto=Object.getPrototypeOf(proto);
}
console.log("object的原型"+proto);
結(jié)果是:GuoyansiEx
Guoyansi
Object
object的原型null
個(gè)人覺(jué)得這些應(yīng)該算是javascript面向?qū)ο蟮木柚涣?小伙伴們自己參考下,根據(jù)需求使用到自己的項(xiàng)目中去吧
相關(guān)文章
Javascript json object 與string 相互轉(zhuǎn)換的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇Javascript json object 與string 相互轉(zhuǎn)換的簡(jiǎn)單實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09Bootstrap Table從服務(wù)器加載數(shù)據(jù)進(jìn)行顯示的實(shí)現(xiàn)方法
Bootstrap-Table是一個(gè)Boostrap的表格插件,能夠?qū)SON數(shù)據(jù)直接顯示在表格中。接下來(lái)通過(guò)本文給大家分享Bootstrap Table從服務(wù)器加載數(shù)據(jù)進(jìn)行顯示的實(shí)現(xiàn)方法,感興趣的朋友一起看看吧2016-09-09JavaScript獲取當(dāng)前時(shí)間向前推三個(gè)月的方法示例
這篇文章主要介紹了JavaScript獲取當(dāng)前時(shí)間向前推三個(gè)月的方法,結(jié)合實(shí)例形式分析了javascript日期與時(shí)間運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-02-02firefox 和 ie 事件處理的細(xì)節(jié),研究,再研究 書(shū)寫(xiě)同時(shí)兼容ie和ff的事件處理代碼
firefox 和 ie 事件處理的細(xì)節(jié),研究,再研究 書(shū)寫(xiě)同時(shí)兼容ie和ff的事件處理代碼2007-04-04JavaScript格式化日期時(shí)間的方法和自定義格式化函數(shù)示例
JavaScript默認(rèn)的時(shí)間格式我們一般情況下不會(huì)用,所以需要進(jìn)行格式化,下面說(shuō)說(shuō)我總結(jié)的JavaScript時(shí)間格式化方法2014-04-04Handtrack.js庫(kù)實(shí)現(xiàn)實(shí)時(shí)監(jiān)測(cè)手部運(yùn)動(dòng)(推薦)
這篇文章主要介紹了實(shí)時(shí)監(jiān)測(cè)手部運(yùn)動(dòng)的 JS 庫(kù),可以實(shí)現(xiàn)很多有趣功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02