function Foo() {...};
let f1 = new Foo();
複製代碼
以上代碼表示建立一個構造函數Foo(),並用new關鍵字實例化該構造函數獲得一個實例化對象f1。這裏稍微補充一下new操做符將函數做爲構造器進行調用時的過程:函數被調用,而後新建立一個對象,而且成了函數的上下文(也就是此時函數內部的this是指向該新建立的對象,這意味着咱們能夠在構造器函數內部經過this參數初始化值),最後返回該新對象的引用。以下圖所示: · 函數
圖的說明:右下角爲圖例,紅色箭頭表示__proto__屬性指向、綠色箭頭表示prototype屬性的指向、棕色實線箭頭表示自己具備的constructor屬性的指向,棕色虛線箭頭表示繼承而來的constructor屬性的指向;藍色方塊表示對象,淺綠色方塊表示函數(這裏爲了更好看清,Foo()僅表明是函數,並非指執行函數Foo後獲得的結果,圖中的其餘函數同理)。圖的中間部分即爲它們之間的聯繫,圖的最左邊即爲例子代碼。this
首先,咱們須要牢記兩點:①__proto__和constructor屬性是對象所獨有的;② prototype屬性是函數所獨有的。可是因爲JS中函數也是一種對象,因此函數也擁有__proto__和constructor屬性,這點是導致咱們產生困惑的很大緣由之一。上圖有點複雜,咱們把它按照屬性分別拆開,而後進行分析:spa
第一,這裏咱們僅留下 __proto__屬性,它是 對象所獨有的,能夠看到__proto__屬性都是由一個對象指向一個對象,即指向它們的原型對象(也能夠理解爲父對象),那麼這個屬性的做用是什麼呢?它的做用就是當訪問一個對象的屬性時,若是該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象(能夠理解爲父對象)裏找,若是父對象也不存在這個屬性,則繼續往父對象的__proto__屬性所指向的那個對象(能夠理解爲爺爺對象)裏找,若是還沒找到,則繼續往上找…直到原型鏈頂端null(能夠理解爲原始人。。。),再往上找就至關於在 null上取值,會報錯(能夠理解爲,再往上就已經不是「人」的範疇了,找不到了,到此結束, null爲原型鏈的終點),由以上這種經過__proto__屬性來鏈接對象直到 null的一條鏈即爲咱們所謂的 原型鏈。第二,接下來咱們看 prototype 屬性:prototype
prototype屬性,別忘了一點,就是咱們前面提到要牢記的兩點中的第二點,它是函數所獨有的,它是從一個函數指向一個對象。它的含義是函數的原型對象,也就是這個函數(其實全部函數均可以做爲構造函數)所建立的實例的原型對象,由此可知:f1.proto===Foo.prototype,它們兩個徹底同樣。那prototype屬性的做用又是什麼呢?它的做用就是包含能夠由特定類型的全部實例共享的屬性和方法,也就是讓該函數所實例化的對象們均可以找到公用的屬性和方法。任何函數在建立的時候,其實會默認同時建立該函數的3d