instanceof 運算符簡介
在JavaScript 中,判斷一個變量的類型嚐嚐會用typeof 運算符,在使用typeof 運算符時採用引用類型存儲值會出現一個問題,無論引用的是什麼類型的對象,它都返回“object”。 ECMAScript 引入了另一個Java 運算符instanceof 來解決這個問題。 instanceof 運算符與typeof 運算符相似,用於識別正在處理的對象的類型。與typeof 方法不同的是,instanceof 方法要求開發者明確地確認對象為某特定類型。例如:
清單1. instanceof 示例
var oStringObject = new String("hello world"); console.log(oStringObject instanceof String); // 輸出"true"這段代碼問的是“變量oStringObject 是否為String 對象的實例?”oStringObject 的確是String 對象的實例,因此結果是”true”。儘管不像typeof 方法那樣靈活,但是在typeof 方法返回“object” 的情況下,instanceof 方法還是很有用的。
instanceof 運算符的常規用法:
通常來講,使用instanceof 就是判斷一個實例是否屬於某種類型。例如:
清單2. instanceof 常規用法
// 判斷foo 是否是Foo 類的實例function Foo(){} var foo = new Foo(); console.log(foo instanceof Foo)//true另外,更重的一點是instanceof 可以在繼承關係中用來判斷一個實例是否屬於它的父類型。例如:
清單3. instanceof 在繼承中關係中的用法
// 判斷foo 是否是Foo 類的實例, 並且是否是其父類型的實例function Aoo(){} function Foo(){} Foo.prototype = new Aoo();//JavaScript 原型繼承var foo = new Foo(); console.log(foo instanceof Foo)//true console.log(foo instanceof Aoo)//true上面的代碼中是判斷了一層繼承關係中的父類,在多層繼承關係中,instanceof 運算符同樣適用。
你真的了解instanceof 操作符嗎?
看了上面的代碼示例,是不是覺得instanceof 操作符很簡單,下面來看點複雜的用法。
清單4. instanceof 複雜用法
console.log(Object instanceof Object);//true console.log(Function instanceof Function);//true console.log(Number instanceof Number);//false console.log(String instanceof String);//false console.log(Function instanceof Object);//true console.log(Foo instanceof Function);//true console.log(Foo instanceof Foo);//false
看了上面的代碼是不是又暈頭轉向了?為什麼Object 和Function instanceof 自己等於true,而其他類instanceof 自己卻又不等於true 呢?如何解釋?要想從根本上了解instanceof 的奧秘,需要從兩個方面著手:1,語言規範中是如何定義這個運算符的。 2,JavaScript 原型繼承機制。
清單5. JavaScript instanceof 運算符代碼
function instance_of(L, R) {//L 表示左表達式,R 表示右表達式var O = R.prototype;// 取R 的顯示原型L = L.__proto__;// 取L 的隱式原型while (true) { if (L === null) return false; if (O === L)// 這裡重點:當O 嚴格等於L 時,返回true return true; L = L.__proto__; } }清單6. Object instanceof Object
// 為了方便表述,首先區分左側表達式和右側表達式ObjectL = Object, ObjectR = Object; // 下面根據規範逐步推演O = ObjectR.prototype = Object.prototype L = ObjectL.__proto__ = Function.prototype // 第一次判斷O != L // 循環查找L 是否還有__proto__ L = Function.prototype.__proto__ = Object.prototype // 第二次判斷O == L // 返回true
清單7. Function instanceof Function
// 為了方便表述,首先區分左側表達式和右側表達式FunctionL = Function, FunctionR = Function; // 下面根據規範逐步推演O = FunctionR.prototype = Function.prototype L = FunctionL.__proto__ = Function.prototype // 第一次判斷O == L // 返回true
清單8. Foo instanceof Foo
// 為了方便表述,首先區分左側表達式和右側表達式FooL = Foo, FooR = Foo; // 下面根據規範逐步推演O = FooR.prototype = Foo.prototype L = FooL.__proto__ = Function.prototype // 第一次判斷O != L // 循環再次查找L 是否還有__proto__ L = Function.prototype.__proto__ = Object.prototype // 第二次判斷O != L // 再次循環查找L 是否還有__proto__ L = Object.prototype.__proto__ = null // 第三次判斷L == null // 返回false
簡析instanceof 在Dojo 繼承機制中的應用
在JavaScript 中,是沒有多重繼承這個概念的,就像Java 一樣。但在Dojo 中使用declare 聲明類時,是允許繼承自多個類的。下面以Dojo 1.6.1 為例。
清單9. Dojo 中多重繼承
dojo.declare("Aoo",null,{}); dojo.declare("Boo",null,{}); dojo.declare("Foo",[Aoo,Boo],{}); var foo = new Foo(); console.log(foo instanceof Aoo);//true console.log(foo instanceof Boo);//false console.log(foo.isInstanceOf(Aoo));//true console.log(foo.isInstanceOf(Boo));//true上面的示例中,Foo 同時繼承自Aoo 和Boo,但當使用instanceof 運算符來檢查foo 是否是Boo 的實例時,返回的是false。實際上,在Dojo 的內部,Foo 仍然只繼承自Aoo,而通過mixin 機制把Boo 類中的方法和屬性拷貝到Foo 中,所以當用instanceof 運算符來檢查是否是Boo 的實例時,會返回false。所以Dojo 為每個類的實例添加了一個新的方法叫isInstanceOf,用這個方法來檢查多重繼承。