注意:本文不是javascript基礎教程,如果你沒有接觸過原型的基本知識,應該先去了解一下,推薦看《javascript高階程式設計(第三版)》第6章:物件導向的程式設計。
上節已經提到,每個函式function都有一個prototype,即原型。這裡再加一句話——每個物件都有一個__proto__,可成為隱式原型。
這個__proto__是一個隱藏的屬性,javascript不希望開發者用到這個屬性值,有的低版本瀏覽器甚至不支援這個屬性值。所以你在Visual Studio 2012這樣很高階很智慧的編輯器中,都不會有__proto__的智慧提示,但是你不用管它,直接寫出來就是了。
上面截圖看來,obj.__proto__和Object.prototype的屬性一樣!這麼巧!
答案就是一樣。
obj這個物件本質上是被Object函式建立的,因此obj.__proto__=== Object.prototype。我們可以用一個圖來表示。
即,每個物件都有一個__proto__屬性,指向建立該物件的函式的prototype。
那麼上圖中的“Object prototype”也是一個物件,它的__proto__指向哪裡?
好問題!
在說明“Object prototype”之前,先說一下自定義函式的prototype。自定義函式的prototype本質上就是和 var obj = {} 是一樣的,都是被Object建立,所以它的__proto__指向的就是Object.prototype。
但是Object.prototype確實一個特例——它的__proto__指向的是null,切記切記!
還有——函式也是一種物件,函式也有__proto__嗎?
又一個好問題!——當然有。
函式也不是從石頭縫裡蹦出來的,函式也是被建立出來的。誰建立了函式呢?——Function——注意這個大寫的“F”。
且看如下程式碼。
以上程式碼中,第一種方式是比較傳統的函式建立方式,第二種是用new Functoin建立。
首先根本不推薦用第二種方式。
這裡只是向大家演示,函式是被Function建立的。
好了,根據上面說的一句話——物件的__proto__指向的是建立它的函式的prototype,就會出現:Object.__proto__ === Function.prototype。用一個圖來表示。
上圖中,很明顯的標出了:自定義函式Foo.__proto__指向Function.prototype,Object.__proto__指向Function.prototype,唉,怎麼還有一個……Function.__proto__指向Function.prototype?這不成了迴圈引用了?
對!是一個環形結構。
其實稍微想一下就明白了。Function也是一個函式,函式是一種物件,也有__proto__屬性。既然是函式,那麼它一定是被Function建立。所以——Function是被自身建立的。所以它的__proto__指向了自身的Prototype。
篇幅不少了,估計也都看煩了。快結束了。
最後一個問題:Function.prototype指向的物件,它的__proto__是不是也指向Object.prototype?
答案是肯定的。因為Function.prototype指向的物件也是一個普通的被Object建立的物件,所以也遵循基本的規則。
OK 本節結束,是不是很亂?
亂很正常。那這一節就讓它先亂著,下一節我們將請另一個老朋友來幫忙,把它理清楚。這位老朋友就是——instanceof。
具體內容,請看下節分解。
---------------------------------------------------------------------------
本文已更新到《深入理解javascript原型和閉包系列》的目錄,更多內容可參見《深入理解javascript原型和閉包系列》。
另外,歡迎關注我的微博。
學習作者教程:《前端JS高階面試》《前端JS基礎面試題》《React.js模擬大眾點評webapp》《zepto設計與原始碼分析》《json2.js原始碼解讀》