今天將延續這篇文章,藉助一個老朋友——instanceof運算符,將經過它以及結合屢次講的原型/原型鏈經典圖來深刻理解原型/原型鏈。javascript
對於原始類型(primitive type)的值,即string
/number
/boolean
,你能夠經過typeof
判斷其類型,可是typeof
在判斷到合成類型(complex type)的值的時候,返回值只有object
/function
,你不知道它究竟是一個object
對象,仍是數組,也不能判斷出Object 下具體是什麼細分的類型,好比 Array
、Date
、RegExp
、Error
等。java
官方對instanceof
運算符的解釋是返回一個布爾值,表示對象是否爲某個構造函數的實例。好比:git
function Foo() {}
var f1 = new Foo();
console.log(f1 instanceof Foo); // true
console.log(f1 instanceof Object); // true
複製代碼
上面代碼中,對象f1
是構造函數Foo
的實例,因此返回true
,可是「f1 instanceof Object」爲何也是true
呢?github
至於爲何等會再解釋,先把instanceof
判斷的規則告訴你們。根據以上代碼看下圖:數組
instanceof
運算符的左邊是實例對象,右邊是構造函數,左邊變量暫稱爲A,右邊變量暫稱爲B。它會檢查右邊構造函數的原型對象(prototype),是否在左邊對象的原型鏈上。函數
通俗一點來說,instanceof
的判斷規則是:instanceof
會檢查整個原型鏈,將沿着A的__proto__
這條線來一直找,同時沿着B的prototype
這條線來一直找,直到能找到同一個引用,即同一個對象,那麼就返回true
。若是找到終點還未重合,則返回false
。即上圖中的 f1
-->__proto__
和 Foo
-->prototype
指向同一個對象,console.log(f1 instanceof Foo)
爲true
。ui
按照以上規則,從新來看看「 f1 instanceof Object 」這句代碼爲何是true
? 根據上圖很容易就能看出來, f1-->__proto__
-->__proto__
和Object
-->prototype
指向同一個對象,console.log(f1 instanceof Object)
爲true
。spa
經過上面的規則,能夠很好地解釋一些比較怪異的現象,例如:prototype
console.log(Object instanceof Function); // true
console.log(Function instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Object instanceof Object); // true
複製代碼
這些就是這篇文章所講的看似很混亂的東西,如今知道爲什麼了吧。設計
但還有一種特殊狀況,就是左邊對象的原型鏈上,只有null
對象。這時,instanceof
判斷會失真。
var obj = Object.create(null);
typeof obj // "object"
Object.create(null) instanceof Object // false
複製代碼
上面代碼中,Object.create(null)
返回一個新對象obj
,它的原型是null
(Object.create
後續會有專門文章介紹)。右邊的構造函數Object
的prototype
屬性,不在左邊的原型鏈上,所以instanceof
就認爲obj
不是Object
的實例。可是,只要一個對象的原型不是null
,instanceof
運算符的判斷就不會失真。
說到這裏,繼續貼上這幅原型/原型鏈的經典圖,是否如今看起來沒那麼複雜了呢。
若是這篇文章你看的比較仔細,再結合剛纔介紹的instanceof
的概念規則,相信能看懂上面這張圖的內容了。
那麼問題又出來了。instanceof
這樣設計,到底有什麼用?到底instanceof
想表達什麼呢?
這就要重點講講繼承了,即instanceof
表示的就是一種繼承關係,或者原型鏈的結構,請看後續文章介紹。
若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!