摘要:的隱式原型是母,母是由構(gòu)造函數(shù)構(gòu)造的,但函數(shù)的隱式原型又是。。。。可能是考慮到它也是由構(gòu)造函數(shù)生成的吧,所以返回的值也是。
首先,我們暫且把object類型和function類型分開來,因?yàn)?function是一個特殊的對象類型,我們這里這是便于區(qū)分,把function類型多帶帶拿出來。順便一提,typeof也是多帶帶把function設(shè)為一種類型,我們可以用typeof來驗(yàn)證我們的猜想。
從上圖中可以看到,所有的橘色箭頭(constructor)都指向function Function(){},所有的黑色箭頭(__proto__)開始有兩條路可以走,但是最后都匯聚在了一起,指向null。而天藍(lán)色箭頭(prototype)不具有連續(xù)性,一般都是一個function指向一個object。然后我們可以得出以下結(jié)論:
所有對象的構(gòu)造函數(shù)(constructor)最終指向function Function( ){ }這個函數(shù),包括他自己。ps:為了方便,我們稱它為母Function。
所有對象的__proto__最終指向null,即一切原型鏈的末端就是null。
所謂的一切源于對象,這里的”對象”指的是Object{}(紅色虛線框內(nèi),也就是Object的prototype)。ps:為了方便,我們在這里叫它母Object。
除了Object的原型(prototype)直接指向母Object,其他所有類型的(構(gòu)造器的)原型(prototype)都先指向一個由母Object派生出來的一個子Object,再指向母Object,F(xiàn)unction的原型為function{}。ps:構(gòu)造器,即構(gòu)造函數(shù)。
哲學(xué)部分:這幅圖包含兩個”先有雞還是先有蛋”的問題:
function(){}是由母Function構(gòu)造的,但它同時又是母Function的原型。。
function(){}的隱式原型(__proto__)是母Object,母Object是由構(gòu)造函數(shù) function Object(){}構(gòu)造的,但函數(shù)function Object(){}的隱式原型又是function (){}。。。。
當(dāng)然除了”先有雞還是先有蛋”,原型鏈中還有一個最最有哲理的問題:
構(gòu)造函數(shù)function Function(){}的構(gòu)造函數(shù)就是他自己,就是說,他自己把自己生下來了。。。。。 = =
至于為什么function(){}有倆個框框,其實(shí)是因?yàn)樗窃椭凶钐厥獾?。它是原型中唯一一個的function類型的,其他的原型都是object類型。可能是考慮到它也是由構(gòu)造函數(shù)Function生成的吧,所以typeof返回的值也是function。
我們再來說一下可能大家都很疑惑的問題,就是原型(prototype)和隱式原型(__proto__)的區(qū)別。
我說一下我的見解。相對于”原型”,我覺得”__proto__”更適合叫做父對象,因?yàn)樵谠玩溨?,?fù)責(zé)連接各個對象的,就是”__proto__”。也就是說,我改寫對象的”prototype”,并不會影響對象在原型鏈中的位置,想脫離或者改變原型鏈,只能是改寫”__proto__”。
在原型鏈中,對象和它的”__proto__”指向的對象的關(guān)系,更像是別的語言中的子類和父類。子類會繼承父類的方法和屬性,而且會和父類保持一樣的類型。
一般來說,”__proto__”都是指向某一個對象的”prototype”屬性,所以對象會繼承的也就是其父對象”prototype”中的屬性和方法,但是并不會繼承其父對象自身的屬性方法。說的可能有點(diǎn)繞,我們舉個栗子:
//以O(shè)bject為原型創(chuàng)建一個對象,obj。 var obj=new Object /*這句話可以翻譯為: var obj={} obj.__proto__=Object.prototype */
這個時候,obj的”__proto__”指向的是Object.prototype,所以obj的父對象是Object.prototype,obj會繼承Object.prototype中的屬性方法,但是并不會繼承Object中的屬性和方法。這時候我們用obj.toString()是可以的,但是用obj.length就會報錯。這是因?yàn)閠oString()是寫在Object.prototype里面的,而length是寫在Object里面的。
在學(xué)習(xí)運(yùn)算符的時候,相比很多初學(xué)者也會有和我一樣的疑問,為什么instanceof向上查找會在prototype里查找,而不在”父對象”中查找。理解我上面所說,大家相比也會明白了吧。就拿上面的例子來說,其實(shí)Object只是obj的構(gòu)造器,構(gòu)造函數(shù)而已,obj真正的父對象是Object.prototype。
那講到這里有的小伙伴就會有疑問了,那我要是想繼承Object里面的屬性怎么辦?其實(shí)也很簡單,設(shè)置obj的”__proto__”指向Object就可以了。不過有一點(diǎn),”__proto__”屬性畢竟是底杠開頭,是官方不想暴露在外面的屬性,能不用的時候最好不要用。其實(shí)就算不用”__proto__”也是可以達(dá)到想要的效果的。Object里面有一個可以創(chuàng)建對象的方法create,用它我們可以輕松達(dá)到我們的要求。舉個栗子:
//以O(shè)bject為原型創(chuàng)建一個對象,obj。 var obj= Object.create(Object) /*這句話可以翻譯為: var obj={} obj.__proto__=Object 再說一下create的用法: Object.create(prototype,[{code}]);//返回一個對象 可以看到,這里有兩個參數(shù),第一個參數(shù)prototype相當(dāng)于創(chuàng)建對象的__proto__,值得話隨便一個對象就可以了,第二個參數(shù)可以不填,里面詳細(xì)寫創(chuàng)建對象的一些屬性和他們的屬性標(biāo)簽。注意,create創(chuàng)建的是一個對象,和new一樣,無論以什么為父對象,返回值都是object。 */
再來說說prototype,通過上圖大家會發(fā)現(xiàn),prototype屬性只是一個函數(shù)和一個對象之間的一個橋梁,在這里為什么要說是橋梁呢,為什么不說是函數(shù)的一個屬性呢?我曾寫過一個例子:
function fa(){} fa.prototype.fname=’fa’ var ch=new fa() ch.fname //’fa’ fa.prototype={fname:’newfa’} //改寫prototype ch.fname //依舊是’fa’, ch.hasOwnProporty(‘fname’) //false ch.__proto__==fa.prototype //false
通過上述代碼大家可以看出來了吧,ch繼承fa時只是讓ch.__proto__指向了fa.prototype指向的地址,而不是指向fa.prototype。所以就導(dǎo)致了改寫fa.prototype并不會影響ch.fname的值。改寫后ch.__proto__不等于fa.prototype了,也就是說ch和fa已經(jīng)半毛錢關(guān)系都沒有了。
基本上到這里,大家都會對原型鏈有一定的認(rèn)識了,至于對象中的特殊存在——function,大家可以自己去探索一下。以上都是自己對于JS中原型鏈的認(rèn)識,如有錯誤歡迎大家指正~
ps:sf的編排好難用 !
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79872.html
摘要:構(gòu)造函數(shù)的屬性指向原型對象原型對象的屬性指向構(gòu)造函數(shù)實(shí)例對象的指向原型對象所有引用類型默認(rèn)都繼承了,而這個繼承也是通過原型鏈實(shí)現(xiàn)的。第一種方式是使用操作符,只要用這個操作符來測試實(shí)例與原型鏈中出現(xiàn)過的構(gòu)造函數(shù),結(jié)果就會返回。 理解對象 首先對象的定義是:無序?qū)傩缘募?,其屬性可以包含基本值、對象或者函?shù)。嚴(yán)格來講,這就相當(dāng)于說對象是一組沒有特定順序的值。對象的每個屬性或方法都有一個名...
摘要:不過,從編程習(xí)慣上,我們應(yīng)該盡量讓對象的指向其構(gòu)造函數(shù),以維持這個慣例總結(jié)原型和原型鏈?zhǔn)菍?shí)現(xiàn)繼承的一種模型原型鏈?zhǔn)强啃纬傻?,它在其中的作用屬于連接的線 原型鏈概念 每個構(gòu)造函數(shù)內(nèi)部都會有一個(constructor,prototype原型對象),而且都會有一個內(nèi)置樹形__proto__屬性用于指向創(chuàng)建它函數(shù)對象的prototype原型,當(dāng)然原型對象也會有__proto__屬性,源源不斷...
摘要:對應(yīng)的關(guān)系圖如下講解了構(gòu)造函數(shù)和原型對象之間的關(guān)系,那么實(shí)例對象和原型對象之間的關(guān)系又是怎么樣的呢下面講解。原型對象的指向的是構(gòu)造函數(shù)和本身沒有屬性,但是其原型對象有該屬性,因此也能獲取到構(gòu)造函數(shù)。 JavaScript進(jìn)階 - 1. 原型和原型鏈的概念 我們好多經(jīng)常會被問道JavaScript原型和原型鏈的概念,還有關(guān)于繼承,new操作符相關(guān)的概念。本文就專門整理了原型和原型鏈的概念...
摘要:在這個情況下我們可能需要使用構(gòu)造函數(shù),其以指定的模式來創(chuàng)造對象。構(gòu)造函數(shù)也有自己的,值為,也通過其屬性關(guān)聯(lián)到。從邏輯上來說,這是以棧的形式實(shí)現(xiàn)的,它叫作執(zhí)行上下文棧。 原文:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ 對象 原型鏈 構(gòu)造函數(shù) 執(zhí)行上下文棧 執(zhí)行上下文 變量對象 活動對象 作用域鏈 閉包 Thi...
閱讀 855·2021-10-13 09:39
閱讀 3732·2021-10-12 10:12
閱讀 1791·2021-08-13 15:07
閱讀 1038·2019-08-29 15:31
閱讀 2913·2019-08-26 13:25
閱讀 1808·2019-08-23 18:38
閱讀 1914·2019-08-23 18:25
閱讀 1878·2019-08-23 17:20