您好,登錄后才能下訂單哦!
小編給大家分享一下JS中prototype、__proto__與constructor怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
1. 前言
作為一名前端工程師,必須搞懂JS中的prototype
、__proto__
與constructor
屬性,相信很多初學(xué)者對(duì)這些屬性存在許多困惑,容易把它們混淆,本文旨在幫助大家理清它們之間的關(guān)系并徹底搞懂它們。這里說(shuō)明一點(diǎn),__proto__
屬性的兩邊是各由兩個(gè)下劃線構(gòu)成(這里為了方便大家看清,在兩下劃線之間加入了一個(gè)空格:_ _proto_ _
),實(shí)際上,該屬性在ES標(biāo)準(zhǔn)定義中的名字應(yīng)該是[[Prototype]]
,具體實(shí)現(xiàn)是由瀏覽器代理自己實(shí)現(xiàn),谷歌瀏覽器的實(shí)現(xiàn)就是將[[Prototype]]
命名為__proto__
,大家清楚這個(gè)標(biāo)準(zhǔn)定義與具體實(shí)現(xiàn)的區(qū)別即可(名字有所差異,功能是一樣的)。本文基于谷歌瀏覽器(版本 72.0.3626.121)的實(shí)驗(yàn)結(jié)果所得。
現(xiàn)在正式開(kāi)始! 讓我們從如下一個(gè)簡(jiǎn)單的例子展開(kāi)討論,并配以相關(guān)的圖幫助理解:
function Foo() {...}; let f1 = new Foo();
以上代碼表示創(chuàng)建一個(gè)構(gòu)造函數(shù)Foo()
,并用new
關(guān)鍵字實(shí)例化該構(gòu)造函數(shù)得到一個(gè)實(shí)例化對(duì)象f1
。這里稍微補(bǔ)充一下new操作符將函數(shù)作為構(gòu)造器進(jìn)行調(diào)用時(shí)的過(guò)程:函數(shù)被調(diào)用,然后新創(chuàng)建一個(gè)對(duì)象,并且成了函數(shù)的上下文(也就是此時(shí)函數(shù)內(nèi)部的this是指向該新創(chuàng)建的對(duì)象,這意味著我們可以在構(gòu)造器函數(shù)內(nèi)部通過(guò)this參數(shù)初始化值),最后返回該新對(duì)象的引用。雖然是簡(jiǎn)簡(jiǎn)單單的兩行代碼,然而它們背后的關(guān)系卻是錯(cuò)綜復(fù)雜的,如下圖所示:
看到這圖別怕,讓我們一步步剖析,徹底搞懂它們!
圖的說(shuō)明:右下角為圖例,紅色箭頭表示__proto__
屬性指向、綠色箭頭表示prototype
屬性的指向、棕色實(shí)線箭頭表示本身具有的constructor
屬性的指向,棕色虛線箭頭表示繼承而來(lái)的constructor
屬性的指向;藍(lán)色方塊表示對(duì)象,淺綠色方塊表示函數(shù)(這里為了更好看清,F(xiàn)oo()僅代表是函數(shù),并不是指執(zhí)行函數(shù)Foo后得到的結(jié)果,圖中的其他函數(shù)同理)。圖的中間部分即為它們之間的聯(lián)系,圖的最左邊即為例子代碼。
2. _ _ proto _ _ 屬性
首先,我們需要牢記兩點(diǎn):①__proto__
和constructor
屬性是對(duì)象所獨(dú)有的;② prototype
屬性是函數(shù)所獨(dú)有的。但是由于JS中函數(shù)也是一種對(duì)象,所以函數(shù)也擁有__proto__
和constructor
屬性,這點(diǎn)是致使我們產(chǎn)生困惑的很大原因之一。上圖有點(diǎn)復(fù)雜,我們把它按照屬性分別拆開(kāi),然后進(jìn)行分析:
??
第一,這里我們僅留下 __proto__
屬性,它是對(duì)象所獨(dú)有的,可以看到__proto__
屬性都是由一個(gè)對(duì)象指向一個(gè)對(duì)象,即指向它們的原型對(duì)象(也可以理解為父對(duì)象),那么這個(gè)屬性的作用是什么呢?它的作用就是當(dāng)訪問(wèn)一個(gè)對(duì)象的屬性時(shí),如果該對(duì)象內(nèi)部不存在這個(gè)屬性,那么就會(huì)去它的__proto__
屬性所指向的那個(gè)對(duì)象(可以理解為父對(duì)象)里找,如果父對(duì)象也不存在這個(gè)屬性,則繼續(xù)往父對(duì)象的__proto__
屬性所指向的那個(gè)對(duì)象(可以理解為爺爺對(duì)象)里找,如果還沒(méi)找到,則繼續(xù)往上找…直到原型鏈頂端null(可以理解為原始人。。。),再往上找就相當(dāng)于在null上取值,會(huì)報(bào)錯(cuò)(可以理解為,再往上就已經(jīng)不是“人”的范疇了,找不到了,到此結(jié)束,null
為原型鏈的終點(diǎn)),由以上這種通過(guò)__proto__
屬性來(lái)連接對(duì)象直到null
的一條鏈即為我們所謂的原型鏈。
3. prototype屬性
第二,接下來(lái)我們看 prototype
屬性:
?
prototype
屬性,別忘了一點(diǎn),就是我們前面提到要牢記的兩點(diǎn)中的第二點(diǎn),它是函數(shù)所獨(dú)有的,它是從一個(gè)函數(shù)指向一個(gè)對(duì)象。它的含義是函數(shù)的原型對(duì)象,也就是這個(gè)函數(shù)(其實(shí)所有函數(shù)都可以作為構(gòu)造函數(shù))所創(chuàng)建的實(shí)例的原型對(duì)象,由此可知:f1.__proto__ === Foo.prototype
,它們兩個(gè)完全一樣。那prototype
屬性的作用又是什么呢?它的作用就是包含可以由特定類型的所有實(shí)例共享的屬性和方法,也就是讓該函數(shù)所實(shí)例化的對(duì)象們都可以找到公用的屬性和方法。任何函數(shù)在創(chuàng)建的時(shí)候,其實(shí)會(huì)默認(rèn)同時(shí)創(chuàng)建該函數(shù)的prototype對(duì)象。
4. constructor屬性
最后,我們來(lái)看一下 constructor
屬性:
??
constructor
屬性也是對(duì)象才擁有的,它是從一個(gè)對(duì)象指向一個(gè)函數(shù),含義就是指向該對(duì)象的構(gòu)造函數(shù),每個(gè)對(duì)象都有構(gòu)造函數(shù)(本身?yè)碛谢蚶^承而來(lái),繼承而來(lái)的要結(jié)合__proto__
屬性查看會(huì)更清楚點(diǎn),如下圖所示),從上圖中可以看出Function這個(gè)對(duì)象比較特殊,它的構(gòu)造函數(shù)就是它自己(因?yàn)镕unction可以看成是一個(gè)函數(shù),也可以是一個(gè)對(duì)象),所有函數(shù)和對(duì)象最終都是由Function構(gòu)造函數(shù)得來(lái),所以constructor
屬性的終點(diǎn)就是Function這個(gè)函數(shù)。
?
感謝網(wǎng)友的指出,這里解釋一下上段中“每個(gè)對(duì)象都有構(gòu)造函數(shù)”這句話。這里的意思是每個(gè)對(duì)象都可以找到其對(duì)應(yīng)的constructor,因?yàn)閯?chuàng)建對(duì)象的前提是需要有constructor,而這個(gè)constructor可能是對(duì)象自己本身顯式定義的或者通過(guò)__proto__
在原型鏈中找到的。而單從constructor這個(gè)屬性來(lái)講,只有prototype對(duì)象才有。每個(gè)函數(shù)在創(chuàng)建的時(shí)候,JS會(huì)同時(shí)創(chuàng)建一個(gè)該函數(shù)對(duì)應(yīng)的prototype對(duì)象,而函數(shù)創(chuàng)建的對(duì)象.__proto__ === 該函數(shù).prototype,該函數(shù).prototype.constructor===該函數(shù)本身
,故通過(guò)函數(shù)創(chuàng)建的對(duì)象即使自己沒(méi)有constructor屬性,它也能通過(guò)__proto__
找到對(duì)應(yīng)的constructor,所以任何對(duì)象最終都可以找到其構(gòu)造函數(shù)(null如果當(dāng)成對(duì)象的話,將null除外)。如下:
5. 總結(jié)
總結(jié)一下:
我們需要牢記兩點(diǎn):①__proto__
和constructor
屬性是對(duì)象所獨(dú)有的;② prototype
屬性是函數(shù)所獨(dú)有的,因?yàn)楹瘮?shù)也是一種對(duì)象,所以函數(shù)也擁有__proto__
和constructor
屬性。
__proto__
屬性的作用就是當(dāng)訪問(wèn)一個(gè)對(duì)象的屬性時(shí),如果該對(duì)象內(nèi)部不存在這個(gè)屬性,那么就會(huì)去它的__proto__
屬性所指向的那個(gè)對(duì)象(父對(duì)象)里找,一直找,直到__proto__
屬性的終點(diǎn)null,再往上找就相當(dāng)于在null上取值,會(huì)報(bào)錯(cuò)。通過(guò)__proto__
屬性將對(duì)象連接起來(lái)的這條鏈路即我們所謂的原型鏈。
prototype
屬性的作用就是讓該函數(shù)所實(shí)例化的對(duì)象們都可以找到公用的屬性和方法,即f1.__proto__ === Foo.prototype
。
constructor
屬性的含義就是指向該對(duì)象的構(gòu)造函數(shù),所有函數(shù)(此時(shí)看成對(duì)象了)最終的構(gòu)造函數(shù)都指向Function。
以上是“JS中prototype、__proto__與constructor怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。