JS原型鏈 詳解及示例代碼
前言
在 segmentfault 上看到這樣一道題目:
var F = function(){}; Object.prototype.a = function(){}; Function.prototype.b = function(){}; var f = new F();
問:f 能取到a,b嗎?原理是什么?
乍一看真的有點(diǎn)懵,仔細(xì)研究了一下,發(fā)現(xiàn)還是對(duì)原型理解不透徹,所以總結(jié)一篇,填個(gè)洞~
Function和Object
在解題之前,先再說說 原型、原型鏈,以及 Function 和 Object 的關(guān)系,這也是本文的重點(diǎn)。
原型
在創(chuàng)建一個(gè)函數(shù)的時(shí)候,會(huì)自動(dòng)為其創(chuàng)建一個(gè)原型對(duì)象,可以通過函數(shù)的prototype屬性訪問到。
創(chuàng)建一個(gè)構(gòu)造函數(shù)的實(shí)例對(duì)象,該實(shí)例對(duì)象內(nèi)部將包含一個(gè)指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對(duì)象。ECMA-262 第5版中管這個(gè)指針叫[[prototype]]。雖然在腳本中沒有標(biāo)準(zhǔn)的方式訪問[[prototype]],但Firefox、 Safari、 Chrome在每個(gè)對(duì)象上都支持一個(gè)屬性 __proto__,用于訪問其構(gòu)造函數(shù)的原型對(duì)象。
重要的事情再說一遍:
構(gòu)造函數(shù)通過 prototype 屬性訪問原型對(duì)象。
實(shí)例對(duì)象通過 [[prototype]] 內(nèi)部屬性訪問原型對(duì)象,瀏覽器實(shí)現(xiàn)了 _proto_ 屬性用于實(shí)例對(duì)象訪問原型對(duì)象。
var F = function () {}; var f = new F(); // 假設(shè)F的原型對(duì)象是 p, 則 // F.prototype === p; // f.__proto__ === p;
再重復(fù)一遍。。prototype說的是構(gòu)造函數(shù)和原型對(duì)象之間的關(guān)系,__proto__說的是實(shí)例對(duì)象和原型對(duì)象之間的關(guān)系。
原型鏈
類 A繼承B,B繼承C……其實(shí)就是A的原型對(duì)象中有指針指向B的原型對(duì)象,而B的原型對(duì)象中有指針指向C的原型對(duì)象……注意是原型對(duì)象之間的聯(lián)系,A B C 這三個(gè)構(gòu)造函數(shù)之間并沒什么關(guān)系,所以才稱為“原型鏈”吧~
假設(shè)a是A的實(shí)例對(duì)象,則 a 的原型鏈為下圖中紫色線條所示,橙色線條連接了構(gòu)造函數(shù)和其原型對(duì)象。
由圖可以看出,原型鏈的末端是Object.prototype.__proto__即null。當(dāng)查找a的某個(gè)屬性或方法時(shí),首先查找a自身有沒有,沒有則沿著原型鏈一直查找,直到找到或者最后到null返回undefined。
Function 和 Object
Function 和 Object 之間的關(guān)系有點(diǎn)繞:
Object 是構(gòu)造函數(shù),既然是函數(shù),那么就是Function的實(shí)例對(duì)象;Function是構(gòu)造函數(shù),但Function.prototype是對(duì)象,既然是對(duì)象,那么就是Object的實(shí)例對(duì)象。
一切對(duì)象都是Object的實(shí)例,一切函數(shù)都是Function的實(shí)例。
Object是Function的實(shí)例,而Function.prototype是Object的實(shí)例。
二者的關(guān)系如下圖所示。
可見,Object作為構(gòu)造函數(shù),它有 prototype 屬性指向 Object.prototype , 作為實(shí)例對(duì)象, 它有 Object.__proto__ 指向Function.prototype。Function是構(gòu)造函數(shù),它有prototype屬性指向Function.prototype,而Function是函數(shù),從而也是Function的實(shí)例,所以它有Function.__proto__指向Function.prototype,從而 Function.__proto__ === Function.prototype 為 true。
可在Chrome控制臺(tái)下進(jìn)行驗(yàn)證,如圖。
原題解析
解決原型鏈問題最好的辦法就是畫圖了,經(jīng)過前面的分析,這個(gè)圖畫起來應(yīng)該不成問題,如下~
f 的原型鏈為藍(lán)色線所畫,所以 f 可以訪問到 a , 不能訪問到 b 。
如果不畫圖,乍一看,可能會(huì)覺得f 可以訪問到 b,那是可能跟我一樣誤認(rèn)為F.prototype指向Function.prototype,但其實(shí)F.prototype是對(duì)象而不是函數(shù),所以它的原型對(duì)象不會(huì)是 Function.prototype。
所以,原型鏈問題一應(yīng)要畫圖啊~
原題擴(kuò)展
在上題中,f 只能訪問 a,不能訪問 b 。但 F 既可以訪問 a ,又可以訪問 b。如果把題修改成下面的樣子, F.b()的結(jié)果是什么呢?為什么呢?可以想一下哦~
var F = function(){}; Object.prototype.a = function(){}; Function.prototype.b = function(){ console.log('F.__proto__') }; F.prototype.b = function (){console.log('F.prototype');};
總結(jié)
讀到這里,有沒有發(fā)現(xiàn)函數(shù)一個(gè)比較特殊的地方?
一般的對(duì)象,只有一個(gè)__proto__屬性用于訪問其構(gòu)造函數(shù)的原型對(duì)象,而對(duì)于函數(shù)來說,它既是函數(shù)又是對(duì)象。
作為函數(shù),它生來就有prototype屬性指向其原型對(duì)象函數(shù)名.prototype。
作為Function的實(shí)例對(duì)象,它有__proto__屬性指向Function.prototype
通常,這兩個(gè)屬性是指向兩個(gè)對(duì)象的,但Function的這兩個(gè)屬性指向相同,都指向Function.prototype。
對(duì)于函數(shù) A( ) 來說,A.prototype 中的方法是供其實(shí)例對(duì)象調(diào)用的,自己并不會(huì)用;當(dāng)A 作為實(shí)例運(yùn)行時(shí),調(diào)用的是A.__proto__ 中的方法。也就是說,作為構(gòu)造函數(shù)使用時(shí),走的是A.prototype這條鏈,方法、屬性賦給其實(shí)例;作為對(duì)象使用時(shí),走的是A.__proto__這條鏈。在不同的場(chǎng)景下,分清它的身份就不會(huì)錯(cuò)了。
整篇下來,感覺自己說的也比較絮叨……不足之處,還請(qǐng)各位指正~ 至于題目,真的不知道該叫什么好。。
愿本文能帶給堅(jiān)持看完的你一些收獲~ ^_^
謝謝大家對(duì)本站的支持,后續(xù)繼續(xù)更新相關(guān)資料,幫助大家學(xué)習(xí)了解這部分知識(shí)!
- js原型鏈原理看圖說明
- JS繼承--原型鏈繼承和類式繼承
- javascript prototype 原型鏈
- javascript學(xué)習(xí)筆記(九)javascript中的原型(prototype)及原型鏈的繼承方式
- javascript學(xué)習(xí)筆記(五)原型和原型鏈詳解
- JavaScript繼承基礎(chǔ)講解(原型鏈、借用構(gòu)造函數(shù)、混合模式、原型式繼承、寄生式繼承、寄生組合式繼承)
- Javascript之旅 對(duì)象的原型鏈之由來
- JS原型、原型鏈深入理解
- 基于JavaScript實(shí)現(xiàn)繼承機(jī)制之原型鏈(prototype chaining)的詳解
- JavaScript中原型和原型鏈詳解
相關(guān)文章
超級(jí)簡易的JS計(jì)算器實(shí)例講解(實(shí)現(xiàn)加減乘除)
下面小編就為大家?guī)硪黄?jí)簡易的JS計(jì)算器實(shí)例講解(實(shí)現(xiàn)加減乘除)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08支付寶小程序從手動(dòng)埋點(diǎn)到自動(dòng)埋點(diǎn)的實(shí)現(xiàn)過程
埋點(diǎn)的意思是在你想要的數(shù)據(jù)節(jié)點(diǎn)出進(jìn)行設(shè)置,可以方便進(jìn)行采集,下面這篇文章主要給大家介紹了關(guān)于支付寶小程序從手動(dòng)埋點(diǎn)到自動(dòng)埋點(diǎn)的相關(guān)資料,需要的朋友可以參考下2022-03-03JavaScript實(shí)現(xiàn)文本目標(biāo)字符替換和一鍵全部替換
這篇文章主要介紹了JavaScript實(shí)現(xiàn)文本目標(biāo)字符替換和一鍵全部替換,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-06-06JavaScript:Div層拖動(dòng)效果實(shí)例代碼
這篇文章介紹了JavaScript:Div層拖動(dòng)效果實(shí)例代碼,有需要的朋友可以參考一下2013-08-08JavaScript實(shí)現(xiàn)的雙向跨域插件分享
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的雙向跨域插件分享,本文實(shí)現(xiàn)把整個(gè)跨域過程抽象出來,封裝成一個(gè)JavaScript插件,需要的朋友可以參考下2015-01-01