JavaScript 中 instanceof 关键字用于判断实例的类型,在某些情况下它并不能正确的判断实例的类型,例如:变量指定的o是Foo类的实例,但 instanceof 关键字判断结果返回 false,但这种情况一般很少发生主要容易集中在一个 closure 函数中。
另一个问题是,在某些浏览器中 instanceof 关键字判断”实例“是否指定”类型“的实例时,是利用”实例“的 不可枚举属性(constructor)来与指定“类型”比较的,但“constructor”在一些浏览器中是允许被修改的。
一个好的办法是,结合 prototype chains( 原型链)来判断实例的类型,但若原型链被恶意修改,它可能也无法绕过上面的问题,不过它相对稳定,正常情况下恶意访问 __proto__ 的属性的可能性,要远远低于 constructor,下面给出一个关于 __instanceof 函数的示例。
var Foo = (function() {
this.A = 10;
})
var foo = new Foo();
console.log(__instanceof(foo, Foo))
console.log(__instanceof(foo, 'Foo'))
以下为 __instanceof 函数的实现。
// 确认是否是指定类型的实例。
var __instanceof = function (instance, type) {
'use strict'
if (typeof type === 'string') {
type = eval(type);
}
if (typeof type !== 'function') {
return false;
}
var x1 = instance instanceof type;
if (x1) {
return true;
}
var x2 = false;
if (instance !== null && instance !== undefined) {
var current = instance.constructor;
if (current === type) {
return true;
}
var __instproto__ = instance;
var __typesource = type.toString();
if (current && current.toString() === __typesource) {
return true;
}
do {
__instproto__ = __instproto__.__proto__;
if (__instproto__) {
x2 = __instproto__.constructor === type;
if (x2) {
return true;
}
x2 = __typesource === __instproto__.constructor.toString();
if (x2) {
return true;
}
}
} while (__instproto__);
}
return x1 || x2;
}