用小豬佩奇說明Javascript的原型和原型鏈

志如發表於2018-05-10

  沒錯,我就是標題黨!你已經成功被我騙進來了。來都來了,那就聊聊再走唄!接下來就聽我一本正經地跟你說道說道。

  Javascript的原型是這門語言的一個重點和難點。看過很多大佬寫的解釋Javascript原型的文章,但是很多對於初學者其實不是很友好,看完之後還是雲裡霧裡。我雖然不敢說能把這個東西解釋的很清楚,但是作為一個前端菜鳥,我可能更知道大家在讀文章的時候會卡在哪一步,所以希望本文能夠幫助到大家。

  在文章開始,我先明確幾個概念,這裡如果你覺得不好理解,就先牢牢地記住它,然後繼續往下閱讀,讀完你就會豁然開朗,相信我!另外,一定要每行每字去讀,勿跳著讀,博主就犯過這樣的錯誤,導致越讀越糊塗,我這裡也儘量壓縮字數,保證你讀的每個字都是有用的。答:“你都忽悠半天了趕緊開始吧!”

  • prototype :每個函式都會有這個屬性,這裡強調,是函式,普通物件是沒有這個屬性的(這裡為什麼說普通物件呢,因為JS裡面,一切皆為物件,所以這裡的普通物件不包括函式物件)。它是建構函式的原型物件;
  • __proto__ :每個物件都有這個屬性,,這裡強調,是物件,同樣,因為函式也是物件,所以函式也有這個屬性。它指向建構函式的原型物件;
  • constructor :這是原型物件上的一個指向建構函式的屬性。

先看程式碼

// Pig的建構函式
function Pig(name, age) {
    this.name = name;
    this.age = age;
}
// 建立一個Pig的例項,小豬佩奇
var Peppa = new Pig('Peppa', 5);
複製程式碼

敲黑板,劃重點,理解這一句整個問題的關鍵,請多重複幾遍。:在例項化的時候,prototype上的屬性會作為原型物件賦值給例項。 也就是說小豬佩奇的原型,就是從Pig.prototype繼承來的寫成程式碼就是這個樣子Peppa.__proto__ === Pig.prototype

用小豬佩奇說明Javascript的原型和原型鏈
Pig是一個函式物件,它是Function物件的一個例項,所以Pig.__proto__ === Function.prototype一定為true。

用小豬佩奇說明Javascript的原型和原型鏈
我們在上面提到了constructor這個屬性,它位於原型物件上並且指向建構函式,所以Pig.prototype.constructor === Pig

用小豬佩奇說明Javascript的原型和原型鏈
至此,我大致捋了一遍這三個屬性的關係,我們再順著這條鏈繼續往深挖一挖。Function.prototype,也就是Function的原型物件。這個原型物件的__proto__指向了Object.prototype。打破砂鍋問到底,Object.prototype.__proto__又指向誰,JS世界裡萬物皆物件,Object似乎已經到了原型鏈的頂端,果然不出我所料,它確實是null。:

用小豬佩奇說明Javascript的原型和原型鏈
你可能要吐槽了,說好的講明白呢,這一坨都被你繞糊塗了,一張圖勝過千言萬語:

用小豬佩奇說明Javascript的原型和原型鏈

解釋一下上面的圖。先看藍色那條線,Pig,Function和Object的建構函式是Function的例項,所以它們的__proto__均指向Function.prototype。這就印證了敲黑板說的那句話,prototype屬性會作為原型物件賦值給例項,每個物件的__proto__都指向原型物件(處於最頂層的Object.prototype除外)。

再看綠色那條,Pig和Function的原型物件是Object的例項,所以它們的__proto__均指向了Object.prototype,也就是Object的原型物件。

淺藍色的線表明了原型的constructor指向了建構函式。

Emmmm,其實也沒那麼複雜對不對?接著說一下原型鏈。正如你在上面圖中所看到的,JS在建立物件的時候,會在新物件上產生一個__proto__的屬性,這個屬性指向了它建構函式的原型的prototype。由此一級一級向上直到到達Object.prototype.proto === null的這個鏈條我們稱之為原型鏈。

關於繼承的概念,本來想寫在一起的,後來想想,內容過多隻會讓文章成為收藏不看系列,所以這塊的內容放在以後的文章裡詳解。各位看官,我想我大致講明白了原型和原型鏈的概念,有什麼錯誤還懇請批評指正。

相關文章