JS中的prototype、__proto__與constructor

1. 上代碼:

function Foo() {...};
    let f1 = new Foo();
複製代碼

以上代碼表示建立一個構造函數Foo(),並用new關鍵字實例化該構造函數獲得一個實例化對象f1。這裏稍微補充一下new操做符將函數做爲構造器進行調用時的過程:函數被調用,而後新建立一個對象,而且成了函數的上下文(也就是此時函數內部的this是指向該新建立的對象,這意味着咱們能夠在構造器函數內部經過this參數初始化值),最後返回該新對象的引用。以下圖所示: · 函數

圖的說明:右下角爲圖例,紅色箭頭表示__proto__屬性指向、綠色箭頭表示prototype屬性的指向、棕色實線箭頭表示自己具備的constructor屬性的指向,棕色虛線箭頭表示繼承而來的constructor屬性的指向;藍色方塊表示對象,淺綠色方塊表示函數(這裏爲了更好看清,Foo()僅表明是函數,並非指執行函數Foo後獲得的結果,圖中的其餘函數同理)。圖的中間部分即爲它們之間的聯繫,圖的最左邊即爲例子代碼。this

2. _ _ proto _ _ 屬性

首先,咱們須要牢記兩點:①__proto__和constructor屬性是對象所獨有的;② prototype屬性是函數所獨有的。可是因爲JS中函數也是一種對象,因此函數也擁有__proto__和constructor屬性,這點是導致咱們產生困惑的很大緣由之一。上圖有點複雜,咱們把它按照屬性分別拆開,而後進行分析:spa

第一,這裏咱們僅留下 __proto__屬性,它是 對象所獨有的,能夠看到__proto__屬性都是由一個對象指向一個對象,即指向它們的原型對象(也能夠理解爲父對象),那麼這個屬性的做用是什麼呢?它的做用就是當訪問一個對象的屬性時,若是該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象(能夠理解爲父對象)裏找,若是父對象也不存在這個屬性,則繼續往父對象的__proto__屬性所指向的那個對象(能夠理解爲爺爺對象)裏找,若是還沒找到,則繼續往上找…直到原型鏈頂端null(能夠理解爲原始人。。。),再往上找就至關於在 null上取值,會報錯(能夠理解爲,再往上就已經不是「人」的範疇了,找不到了,到此結束, null爲原型鏈的終點),由以上這種經過__proto__屬性來鏈接對象直到 null的一條鏈即爲咱們所謂的 原型鏈

3. prototype屬性

第二,接下來咱們看 prototype 屬性:prototype

prototype屬性,別忘了一點,就是咱們前面提到要牢記的兩點中的第二點,它是函數所獨有的,它是從一個函數指向一個對象。它的含義是函數的原型對象,也就是這個函數(其實全部函數均可以做爲構造函數)所建立的實例的原型對象,由此可知:f1.proto===Foo.prototype,它們兩個徹底同樣。那prototype屬性的做用又是什麼呢?它的做用就是包含能夠由特定類型的全部實例共享的屬性和方法,也就是讓該函數所實例化的對象們均可以找到公用的屬性和方法。任何函數在建立的時候,其實會默認同時建立該函數的3d

4. constructor屬性

constructor屬性也是對象才擁有的,它是從一個對象指向一個函數,含義就是指向該對象的構造函數,每一個對象都有構造函數(自己擁有或繼承而來,繼承而來的要結合__proto__屬性查看會更清楚點,以下圖所示),從上圖中能夠看出Function這個對象比較特殊,它的構造函數就是它本身(由於Function能夠當作是一個函數,也能夠是一個對象),全部函數和對象最終都是由Function構造函數得來,因此constructor屬性的終點就是Function這個函數。

每一個對象都有構造函數:


這裏的意思是每一個對象均可以找到其對應的constructor,由於建立對象的前提是須要有constructor,而這個constructor多是對象本身自己顯式定義的或者經過__proto__在原型鏈中找到的。而單從constructor這個屬性來說,只有prototype對象纔有。每一個函數在建立的時候,JS會同時建立一個該函數對應的prototype對象,而函數建立的對象.__proto__ === 該函數.prototype,該函數.prototype.constructor===該函數自己,故經過函數建立的對象即便本身沒有constructor屬性,它也能經過__proto__找到對應的constructor,因此任何對象最終均可以找到其構造函數(null若是當成對象的話,將null除外)。

5. 總結

總結一下:

  1. 咱們須要牢記兩點:①__proto__和constructor屬性是對象所獨有的;② prototype屬性是函數所獨有的,由於函數也是一種對象,因此函數也擁有__proto__和constructor屬性。
  2. __proto__屬性的做用就是當訪問一個對象的屬性時,若是該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象(父對象)裏找,一直找,直到__proto__屬性的終點null,再往上找就至關於在null上取值,會報錯。經過__proto__屬性將對象鏈接起來的這條鏈路即咱們所謂的原型鏈。
  3. prototype屬性的做用就是讓該函數所實例化的對象們均可以找到公用的屬性和方法,即f1.proto === Foo.prototype。
  4. constructor屬性的含義就是指向該對象的構造函數,全部函數(此時當作對象了)最終的構造函數都指向Function。
相關文章
相關標籤/搜索