今天将延續這篇文章,借助一個老朋友——instanceof運算符,将通過它以及結合多次講的原型/原型鍊經典圖來深入了解原型/原型鍊。
對于原始類型(primitive type)的值,即string/number/boolean,你可以通過typeof判斷其類型,但是typeof在判斷到合成類型(complex type)的值的時候,傳回值隻有object/function,你不知道它到底是一個object對象,還是數組,也不能判斷出Object 下具體是什麼細分的類型,比如 Array、Date、RegExp、Error 等。
官方對
instanceof
運算符的解釋是傳回一個布爾值,表示對象是否為某個構造函數的執行個體。比如:
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呢?
至于為什麼等會再解釋,先把instanceof判斷的規則告訴大家。根據以上代碼看下圖:
instanceof
運算符的左邊是執行個體對象,右邊是構造函數,左邊變量暫稱為A,右邊變量暫稱為B。它會檢查右邊構造函數的原型對象(prototype),是否在左邊對象的原型鍊上。
通俗一點來講,instanceof的判斷規則是:
instanceof會檢查整個原型鍊,将沿着A的__proto__這條線來一直找,同時沿着B的prototype這條線來一直找,直到能找到同一個引用,即同一個對象,那麼就傳回true。如果找到終點還未重合,則傳回false。即上圖中的 f1-->__proto__ 和 Foo-->prototype 指向同一個對象,console.log(f1 instanceof Foo)為true。
按照以上規則,重新來看看“ f1 instanceof Object ”這句代碼為什麼是true? 根據上圖很容易就能看出來, f1-->__proto__-->__proto__ 和Object-->prototype 指向同一個對象,console.log(f1 instanceof Object)為true。
通過上面的規則,可以很好地解釋一些比較怪異的現象,例如:
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部落格點贊和關注,感激不盡!