做爲一名前端開發者,咱們都知道JS是單繼承的,而Object.prototype是原型鏈的頂端,全部對象從它繼承了包括toString()、valueOf()等等公共屬性。javascript
首先Object
和Function
都是構造函數,而全部的構造函數都是Function
的實例對象。 所以Object
是Function
的實例對象;而Function.prototype
是Object
的實例對象。因此這裏就引申出了一個有意思的雞和蛋的問題:前端
Object instanceof Function // true
Function instanceof Object // true
Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true
複製代碼
那麼Object
和Function
,誰是雞誰是蛋呢?java
接下來就來深刻探究下上面這段代碼所引發的雞生蛋蛋生雞問題,從下面這張原型/原型鏈經典圖入手,在這個過程當中深刻了解 Object.prototype
、Function.prototype
、function Object()
、function Function()
之間的關係,這個過程可能有點燒腦,畢竟是JS的一大玄學嘛。git
原型鏈的盡頭就是Object.prototype
(不考慮 null
的狀況下)。全部對象均從Object.prototype
繼承toString() 等公共屬性。github
Object.prototype
表示 Object
的原型對象,實際上Object.prototype
並非經過Object
函數建立的,爲何呢?看以下代碼:瀏覽器
function Dog() {
this.name = '川普';
}
var dog = new Dog();
dog.__proto__ === Dog.prototype; // true
複製代碼
實例對象的__proto__
會指向構造函數的prototype
,即dog.__proto__
指向 Dog.prototype
,可是Object.prototype.__proto__
又是 null
,因此 Object.prototype
並非經過 Object
函數建立的,那它如何生成的?其實 Object.prototype
是瀏覽器底層根據 ECMAScript 規範創造的一個對象,因此在經典圖裏面只是看起來Object.prototype
是經過 Object
函數建立的,實際上並非。函數
Function.prototype
和Function.__proto__
爲同一對象。ui
這也意味着:Object
/Array
等等構造函數本質上和Function
同樣,均繼承於Function.prototype
,從經典圖上來看都是經過new Function
構造出來的。this
固然,Function.prototype
對象是一個函數(對象),其__proto__
屬性指向 Object.prototype
,即Function.prototype
會直接繼承root(Object.prototype
)。spa
經過這點咱們能夠弄清繼承的原型鏈:Function|Object|Array...--->Function.prototype--->Object.prototype(root)
。以下圖所示:
Object
做爲構造函數時,其__proto__
屬性指向 Function.prototype
,即:
Object.__proto__ === Function.prototype // true
複製代碼
從經典圖來看:
使用 new Object()
建立實例對象o1時,實例對象o1的 __proto__
屬性指向構造函數的 prototype
屬性,對應上圖就是 Object.prototype
,即o1.__proto__ === Object.prototype
結果爲true
。
Function.prototype
指向的對象,它的__proto__
會指向Object.prototype
,由於Function.prototype
指向的對象也是一個普通的被Object
建立的對象,因此也遵循基本的規則。
Function
也是一個函數對象,也有__proto__
屬性,既然是函數,那麼它必定是被Function
建立,因此Function
是被自身建立的,因此它的__proto__
指向了自身的Prototype
:
Function.__proto__ === Function.prototype // true
複製代碼
到這裏就有點燒腦了吧,咱們再看下雞生蛋蛋生雞問題。
由上面可知,Object
構造函數繼承了Function.prototype
,同時Function
構造函數繼承了Object.prototype
,這裏就產生了雞和蛋的問題。爲何會出現這種問題呢?必須首先更深刻一層去理解Function.prototype
這個對象,由於它是致使Function instanceof Object
和Object instanceof Function
都爲true
的緣由。
// Object instanceof Function 即
Object.__proto__ === Function.prototype // true
// Function instanceof Object 即
Function.__proto__.__proto__ === Object.prototype // true
// Object instanceof Object 即
Object.__proto__.__proto__ === Object.prototype // true
// Function instanceof Function 即
Function.__proto__ === Function.prototype // true
複製代碼
根據JS規範,Function.prototype
又是個不一樣於通常函數(對象)的函數(對象),其中:
Function.prototype
像普通函數同樣能夠調用,但老是返回undefined
。Function
的實例,即普通函數繼承於Function.prototype
。即func.__proto__ === Function.prototype
。Function.prototype
繼承於Object.prototype
,而且沒有prototype
這個屬性。Function.prototype
實際上是個另類的函數,能夠獨立於/先於Function
產生。而Object
自己是個(構造)函數,是Function
的實例,即Object.__proto__
就是Function.prototype
。
總結:先有Object.prototype
(原型鏈頂端),Function.prototype
繼承Object.prototype
而產生,最後,Function
和Object
和其它構造函數繼承Function.prototype
而產生。
看到這裏估計也都看煩了,是否是仍是有點混亂呀?亂也很正常。那這篇文章就先讓它亂着,下一篇咱們將請另外一個老朋友來幫忙,把它完全理清楚,這位老朋友就是——instanceof
,那就且聽請下回分解咯。
若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!