從instanceof身上深刻理解原型/原型鏈

今天將延續這篇文章,藉助一個老朋友——instanceof運算符,將經過它以及結合屢次講的原型/原型鏈經典圖來深刻理解原型/原型鏈。javascript

對於原始類型(primitive type)的值,即string/number/boolean,你能夠經過typeof判斷其類型,可是typeof在判斷到合成類型(complex type)的值的時候,返回值只有object/function,你不知道它究竟是一個object對象,仍是數組,也不能判斷出Object 下具體是什麼細分的類型,好比 ArrayDateRegExpError 等。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)trueui

按照以上規則,從新來看看「 f1 instanceof Object 」這句代碼爲何是true? 根據上圖很容易就能看出來, f1-->__proto__-->__proto__Object-->prototype 指向同一個對象,console.log(f1 instanceof Object)truespa

經過上面的規則,能夠很好地解釋一些比較怪異的現象,例如: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,它的原型是nullObject.create後續會有專門文章介紹)。右邊的構造函數Objectprototype屬性,不在左邊的原型鏈上,所以instanceof就認爲obj不是Object的實例。可是,只要一個對象的原型不是nullinstanceof運算符的判斷就不會失真。

說到這裏,繼續貼上這幅原型/原型鏈的經典圖,是否如今看起來沒那麼複雜了呢。

若是這篇文章你看的比較仔細,再結合剛纔介紹的instanceof的概念規則,相信能看懂上面這張圖的內容了。

那麼問題又出來了。instanceof這樣設計,到底有什麼用?到底instanceof想表達什麼呢?

這就要重點講講繼承了,即instanceof表示的就是一種繼承關係,或者原型鏈的結構,請看後續文章介紹。

若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!

相關文章
相關標籤/搜索