淺談JS原型對(duì)象和原型鏈
在Javascript中,萬(wàn)物皆對(duì)象,但對(duì)象也有區(qū)別,大致可以分為兩類(lèi),即:普通對(duì)象(Object)和函數(shù)對(duì)象(Function)。
一般而言,通過(guò)new Function產(chǎn)生的對(duì)象是函數(shù)對(duì)象,其他對(duì)象都是普通對(duì)象。
舉例說(shuō)明:
function f1(){ //todo } var f2 = function(){ //todo }; var f3 = new Function('x','console.log(x)'); var o1 = {}; var o2 = new Object(); var o3 = new f1(); console.log( typeof f1,//function typeof f2,//function typeof f3,//function typeof o1,//object typeof o2,//object typeof o3 //object ); >> function function function object object object
f1屬于函數(shù)的聲明,最常見(jiàn)的函數(shù)定義方式,f2實(shí)際上是一個(gè)匿名函數(shù),把這個(gè)匿名函數(shù)賦值給了f2,屬于函數(shù)表達(dá)式,f3不常見(jiàn),但也是一種函數(shù)對(duì)象。
Function是JS自帶的對(duì)象,f1,f2在創(chuàng)建的時(shí)候,JS會(huì)自動(dòng)通過(guò)new Function()的方式來(lái)構(gòu)建這些對(duì)象,因此,這三個(gè)對(duì)象都是通過(guò)new Function()創(chuàng)建的。
在Javascript中創(chuàng)建對(duì)象有兩種方式:對(duì)象字面量和使用new表達(dá)式,o1和o2的創(chuàng)建恰好對(duì)應(yīng)了這兩種方式,重點(diǎn)講一下o3, 如果用Java和C#的思路來(lái)理解的話(huà),o3是f1的實(shí)例對(duì)象,o3和f1是同一類(lèi)型,至少我以前這么認(rèn)為,其實(shí)不然…
那么怎么理解呢? 很簡(jiǎn)單,看o3是不是通過(guò)new Function產(chǎn)生的, 顯然不是,既然不是函數(shù)對(duì)象,那就是普通對(duì)象 。
通過(guò)對(duì)函數(shù)對(duì)象和普通對(duì)象的簡(jiǎn)單理解之后,我們?cè)賮?lái)了解一下Javascript中的原型和原型鏈:
在JS中,每當(dāng)創(chuàng)建一個(gè)函數(shù)對(duì)象f1 時(shí),該對(duì)象中都會(huì)內(nèi)置一些屬性,其中包括prototype和__proto__, prototype即原型對(duì)象,它記錄著f1的一些屬性和方法。
需要注意的是,prototype 對(duì)f1是不可見(jiàn)的,也就是說(shuō),f1不會(huì)查找prototype中的屬性和方法。
function f(){} f.prototype.foo = "abc"; console.log(f.foo); //undefined
那么,prototype有什么用呢? 其實(shí)prototype的主要作用就是繼承。 通俗一點(diǎn)講,prototype中定義的屬性和方法都是留給自己的“后代”用的,因此,子類(lèi)完全可以訪問(wèn)prototype中的屬性和方法。
想要知道f1是如何把prototype留給“后代”,我們需要了解一下JS中的原型鏈,此時(shí),JS中的 __proto__ 入場(chǎng)了,這哥們長(zhǎng)的很奇特,隱藏的也很深,以致于你經(jīng)常見(jiàn)不到它,但它在普通對(duì)象和函數(shù)對(duì)象中都存在, 它的作用就是保存父類(lèi)的prototype對(duì)象,JS在通過(guò)new 表達(dá)式創(chuàng)建一個(gè)對(duì)象的時(shí)候,通常會(huì)把父類(lèi)的prototype賦值給新對(duì)象的__proto__屬性,這樣,就形成了一代代傳承…
function f(){} f.prototype.foo = "abc"; var obj = new f(); console.log(obj.foo); //abc
現(xiàn)在我們知道,obj中__proto__保存的是f的prototype, 那么f的prototype中的__proto__中保存的是什么呢? 看下圖:
如圖所示,f.prototype的__proto__中保存的是Object.prototype,Object.prototype對(duì)象中也有__proto__,而從輸出結(jié)果看,Object.prototype.__proto__ 是null,表示obj對(duì)象原型鏈的終結(jié)。如下圖所示:
obj對(duì)象擁有這樣一個(gè)原型鏈以后,當(dāng)obj.foo執(zhí)行時(shí),obj會(huì)先查找自身是否有該屬性,但不會(huì)查找自己的prototype,當(dāng)找不到foo時(shí),obj就沿著原型鏈依次去查找…
在上面的例子中,我們?cè)趂的prototype上定義了foo屬性,這時(shí)obj就會(huì)在原型鏈上找到這個(gè)屬性并執(zhí)行。
最后,用幾句話(huà)總結(jié)一下本文中涉及到的重點(diǎn):
- 原型鏈的形成真正是靠__proto__ 而非prototype,當(dāng)JS引擎執(zhí)行對(duì)象的方法時(shí),先查找對(duì)象本身是否存在該方法,如果不存在,會(huì)在原型鏈上查找,但不會(huì)查找自身的prototype。
- 一個(gè)對(duì)象的__proto__記錄著自己的原型鏈,決定了自身的數(shù)據(jù)類(lèi)型,改變__proto__就等于改變對(duì)象的數(shù)據(jù)類(lèi)型。
- 函數(shù)的prototype不屬于自身的原型鏈,它是子類(lèi)創(chuàng)建的核心,決定了子類(lèi)的數(shù)據(jù)類(lèi)型,是連接子類(lèi)原型鏈的橋梁。
- 在原型對(duì)象上定義方法和屬性的目的是為了被子類(lèi)繼承和使用。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
相關(guān)文章
JavaScript中判斷為整數(shù)的多種方式及保留兩位小數(shù)的方法
這篇文章主要介紹了JavaScript中判斷為整數(shù)的多種方式,以及保留兩位小數(shù)的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09G6?TreeGraph樹(shù)圖節(jié)點(diǎn)懶加載使用場(chǎng)景示例
這篇文章主要為大家介紹了G6?TreeGraph樹(shù)圖節(jié)點(diǎn)懶加載使用場(chǎng)景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10一些Javascript的IE和Firefox(火狐)兼容性的問(wèn)題總結(jié)及常用例子
下面是一些Javascript的IE和Firefox(火狐)兼容性的常用例子2009-05-05js實(shí)現(xiàn)input的賦值小結(jié)
這篇文章主要介紹了js實(shí)現(xiàn)input的賦值問(wèn)題小結(jié),在實(shí)際的開(kāi)發(fā)中,為了頁(yè)面的美觀,可能用到一些框架,比如EasyUI框架,文中介紹了easyui的input框賦值代碼,感興趣的朋友一起看看吧2023-12-12解決 window.onload 被覆蓋的問(wèn)題方法
這篇文章主要介紹了解決 window.onload 被覆蓋的問(wèn)題方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01js猜數(shù)字小游戲的簡(jiǎn)單實(shí)現(xiàn)代碼
這篇文章介紹了js猜數(shù)字小游戲的簡(jiǎn)單實(shí)現(xiàn)代碼,很好玩的游戲哦,可以看看你的智商 是否驚人額2013-07-07