js中的instanceof運算符
MDN給出的解釋是:
instanceof
運算符用於檢測構造函數的 prototype
屬性是否出現在某個實例對象的原型鏈上。
看到這里我們就明白了instanceof是與原型和原型鏈有關系的,在弄懂instanceof之前我們就必須要了解什么是原型和原型鏈,關於原型和原型鏈詳細的解釋可以翻看我的另一篇博客徹底理解js的原型和原型鏈
語法:
object instanceof constructor
object ——> 某個實例對象
constructor ——>某個構造函數
實例:
// 定義構造函數
function C(){}
function D(){}
//實例化對象
var o = new C();
o instanceof C; // true,因為 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因為 D.prototype 不在 o 的原型鏈上
o instanceof Object; // true,因為 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object; // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype 指向了一個空對象,這個空對象不在 o 的原型鏈上.
D.prototype = new C(); // 繼承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因為 C.prototype 現在在 o3 的原型鏈上
辨析instanceof和typeof:
instanceof的功能類似於typeof,都是判斷類型。對於值的類型,如string/number/boolean我們都可以通過typeof判斷,但是typeof在判斷引用類型時,返回值只有object/function,你不知道它到底是一個object對象,還是數組,還是new Number等等。聽着還是有點模糊,那么我們通過一段代碼來更好的理解typeof的判斷類型是什么
var a = 18; var b = 'smile'; var c = true; var d = []; var e = {}; function f() { } console.log(typeof (a));//number console.log(typeof (b));//string console.log(typeof (c));//boolean console.log(typeof (d));//object console.log(typeof (e));//object console.log(typeof (f));//function
那么instanceof又是怎么判斷的呢?
我們先假設有一個函數A,A有一個實例化對象a,instanceof的判斷規則是沿着a的__proto__這條線去找,同時沿着A的prototype這條線去找,如果兩條線能找到同一個引用,即同一個對象,就返回true,如果找到終點還沒有重合就返回false.同樣,我們也將通過一段代碼來理解instance的判斷類型
function A() { } var a = new A(); var b = []; console.log(a instanceof A);//true console.log(A instanceof Function);//true console.log(b instanceof Array);//true console.log(a instanceof Array);//false
擴展
其實對於類型的判斷我們還可以使用constructor,至於constructor的原理在這里就不過多解釋了,想了解的可以翻看我的另一篇博客JS的原型和原型鏈。
var a = 4; var arr = []; var obj = {}; function fun(){}; console.log(a.constructor === Number);//true console.log(arr.constructor === Array);//true console.log(obj.constructor === Object);//true console.log(fun.constructor === Function);//true
雖然constructor既可以判斷基本數據類型又可以判斷引用類型,但是它還是存在很多弊端的。
比如它會出現跨框架問題(instanceof也存在),理想情況(單框架)下, var arr = new Array(), arr 自然是Array的實例,檢測結果當然准確。但具體應用中,如果使用多個框架(使用frame),瀏覽器中就會存在多個 window(Global)對象,每個 window 又都有自己的 Array 等一套構造函數,它們一一對應,卻並不相等。解釋起來很拗口,其實道理很簡單:在中國你說家在首都,誰都知道指的是北京。在美國如果你也說家在首都,別人又會理所當然地覺得你在講華盛頓。每個國家(框架、執行環境)都有自己的“首都(原型對象)”,但這個“首都”卻指向不同的位置(對象)。“首都”因所屬國家的不同而不同,Array因所屬的window不同而不同。所以使用 instanceof 的時候要確保“同一框架”這個前提條件。此外constructor還可能因為實現對象繼承時的疏忽導致錯誤結果,因為我們自己手動改變了默認的原型對象。