我在寫一篇圖解 prototype
和 __proto__
的區別時,搜資料搜到了一個有意思的現象,下面這兩個運算返回的結果是一樣的:
Function instanceof Object;//true
Object instanceof Function;//true複製程式碼
這個是怎麼一回事呢?要從運算子 instanceof
說起。
一、instanceof究竟是運算什麼的?
我曾經簡單理解 instanceof
只是檢測一個物件是否是另個物件 new
出來的例項(例如var a = new Object(),a instanceof Object返回true),但實際 instanceof
的運算規則上比這個更復雜。
首先w3c上有官方解釋(傳送門,有興趣的同學可以去看看),但是一如既往地讓人無法一目瞭然地看懂……
知乎上有同學把這個解釋翻譯成人能讀懂的語言(傳送門),看起來似乎明白一些了:
//假設instanceof運算子左邊是L,右邊是R
L instanceof R //instanceof運算時,通過判斷L的原型鏈上是否存在R.prototype
L.__proto__.__proto__ ..... === R.prototype ? //如果存在返回true 否則返回false複製程式碼
注意:instanceof
運算時會遞迴查詢L的原型鏈,即 L.__proto__.__proto__.__proto__.__proto__...
直到找到了或者找到頂層為止。
所以一句話理解 instanceof
的運算規則為:
instanceof
檢測左側的 __proto__
原型鏈上,是否存在右側的 prototype
原型。
二、圖解構造器Function和Object的關係
我們再配合程式碼來看一下就明白了:
//①構造器Function的構造器是它自身
Function.constructor=== Function;//true
//②構造器Object的構造器是Function(由此可知所有構造器的constructor都指向Function)
Object.constructor === Function;//true
//③構造器Function的__proto__是一個特殊的匿名函式function() {}
console.log(Function.__proto__);//function() {}
//④這個特殊的匿名函式的__proto__指向Object的prototype原型。
Function.__proto__.__proto__ === Object.prototype//true
//⑤Object的__proto__指向Function的prototype,也就是上面③中所述的特殊匿名函式
Object.__proto__ === Function.prototype;//true
Function.prototype === Function.__proto__;//true複製程式碼
三、當構造器Object和Function遇到instanceof
我們回過頭來看第一部分那個“奇怪的現象”,從上面那個圖中我們可以看到:
Function.__proto__.__proto__ === Object.prototype;//true
Object.__proto__ === Function.prototype;//true複製程式碼
所以再看回第一點中我們說的 instanceof
的運算規則,Function instanceof Object
和 Object instanceof Function
運算的結果當然都是true啦!
如果看完以上,你還覺得上面的關係看暈了的話,只需要記住下面兩個最重要的關係,其他關係就可以推匯出來了:
所有的構造器的
constructor
都指向Function
Function
的prototype
指向一個特殊匿名函式,而這個特殊匿名函式的__proto__
指向Object.prototype
至於 prototype
和 __proto__
的關係如何推導,可以參考我寫的上一篇部落格《三張圖搞懂JavaScript的原型物件與原型鏈》