instanceof
instanceof
运算符测试以查看构造函数的 prototype
属性是否出现在对象的原型链中的任何位置。返回值是一个布尔值。它的行为可以通过 Symbol.hasInstance
自定义。
试试看
语法
object instanceof constructor
参数
对象
-
要测试的对象。
constructor
-
要测试的构造函数。
异常
TypeError
-
如果
constructor
不是对象,则抛出。如果constructor
没有[Symbol.hasInstance]()
方法,它也必须是一个函数。
描述
instanceof
运算符测试 constructor.prototype
是否存在于 object
的原型链中。这通常(尽管并非总是如此)意味着 object
是用 constructor
构造的。
// defining constructors
function C() {}
function D() {}
const o = new C();
// true, because: Object.getPrototypeOf(o) === C.prototype
o instanceof C;
// false, because D.prototype is nowhere in o's prototype chain
o instanceof D;
o instanceof Object; // true, because:
C.prototype instanceof Object; // true
// Re-assign `constructor.prototype`: you should
// rarely do this in practice.
C.prototype = {};
const o2 = new C();
o2 instanceof C; // true
// false, because C.prototype is nowhere in
// o's prototype chain anymore
o instanceof C;
D.prototype = new C(); // add C to [[Prototype]] linkage of D
const o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true since C.prototype is now in o3's prototype chain
请注意,如果在创建对象后重新分配 constructor.prototype
(通常不建议这样做),instanceof
测试的值可能会发生变化。它也可以通过使用 Object.setPrototypeOf
更改 object
的原型来更改。
类以相同的方式运行,因为类也有 prototype
属性。
class A {}
class B extends A {}
const o1 = new A();
// true, because Object.getPrototypeOf(o1) === A.prototype
o1 instanceof A;
// false, because B.prototype is nowhere in o1's prototype chain
o1 instanceof B;
const o2 = new B();
// true, because Object.getPrototypeOf(Object.getPrototypeOf(o2)) === A.prototype
o2 instanceof A;
// true, because Object.getPrototypeOf(o2) === B.prototype
o2 instanceof B;
对于 绑定函数,instanceof
在目标函数上查找 prototype
属性,因为绑定函数没有 prototype
。
class Base {}
const BoundBase = Base.bind(null, 1, 2);
console.log(new Base() instanceof BoundBase); // true
instanceof 和 Symbol.hasInstance
如果 constructor
有 Symbol.hasInstance
方法,则该方法将优先调用,并将 object
作为其唯一参数,并将 constructor
作为 this
。
// This class allows plain objects to be disguised as this class's instance,
// as long as the object has a particular flag as its property.
class Forgeable {
static isInstanceFlag = Symbol("isInstanceFlag");
static [Symbol.hasInstance](obj) {
return Forgeable.isInstanceFlag in obj;
}
}
const obj = { [Forgeable.isInstanceFlag]: true };
console.log(obj instanceof Forgeable); // true
因为默认情况下所有函数都从 Function.prototype
继承,所以大多数情况下,Function.prototype[Symbol.hasInstance]()
方法指定了当右侧是函数时 instanceof
的行为。有关 instanceof
的确切算法,请参阅 Symbol.hasInstance
页面。
instanceof 和多个领域
JavaScript 执行环境(窗口、框架等)都处于其自己的领域中。这意味着它们具有不同的内置功能(不同的全局对象、不同的构造函数等)。这可能会导致意外的结果。例如,[] instanceof window.frames[0].Array
将返回 false
,因为 Array.prototype !== window.frames[0].Array.prototype
,并且当前领域中的数组从前者继承。
这可能一开始没有意义,但对于处理多个框架或窗口的脚本以及通过函数将对象从一个上下文传递到另一个上下文,这将是一个有效的且强烈的問題。例如,您可以使用 Array.isArray()
安全地检查给定对象是否实际上是一个数组,而忽略它来自哪个领域。
例如,要检查 Node
是否是另一个上下文中的 SVGElement
,您可以使用 myNode instanceof myNode.ownerDocument.defaultView.SVGElement
。
示例
将 instanceof 与 String 一起使用
以下示例显示了 instanceof
与 String
对象的行为。
const literalString = "This is a literal string";
const stringObject = new String("String created with constructor");
literalString instanceof String; // false, string primitive is not a String
stringObject instanceof String; // true
literalString instanceof Object; // false, string primitive is not an Object
stringObject instanceof Object; // true
stringObject instanceof Date; // false
将 instanceof 与 Date 一起使用
以下示例显示了 instanceof
与 Date
对象的行为。
const myDate = new Date();
myDate instanceof Date; // true
myDate instanceof Object; // true
myDate instanceof String; // false
使用 Object.create() 创建的对象
以下示例显示了 instanceof
与使用 Object.create()
创建的对象的行为。
function Shape() {}
function Rectangle() {
Shape.call(this); // call super constructor.
}
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
const rect = new Rectangle();
rect instanceof Object; // true
rect instanceof Shape; // true
rect instanceof Rectangle; // true
rect instanceof String; // false
const literalObject = {};
const nullObject = Object.create(null);
nullObject.name = "My object";
literalObject instanceof Object; // true, every object literal has Object.prototype as prototype
({}) instanceof Object; // true, same case as above
nullObject instanceof Object; // false, prototype is end of prototype chain (null)
演示 mycar 是 Car 类型和 Object 类型
以下代码创建了一个 Car
对象类型和该对象类型的实例 mycar
。instanceof
运算符演示了 mycar
对象是 Car
类型和 Object
类型。
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const mycar = new Car("Honda", "Accord", 1998);
const a = mycar instanceof Car; // returns true
const b = mycar instanceof Object; // returns true
不是 instanceof
要测试对象是否不是特定构造函数的 instanceof
,您可以执行
if (!(mycar instanceof Car)) {
// Do something, like:
// mycar = new Car(mycar)
}
这与
if (!mycar instanceof Car) {
// unreachable code
}
这将始终为 false
。(!mycar
将在 instanceof
之前进行评估,因此您始终尝试了解布尔值是否为 Car
的实例)。
覆盖 instanceof 的行为
使用 instanceof
的一个常见陷阱是相信如果 x instanceof C
,那么 x
是使用 C
作为构造函数创建的。这不是真的,因为 x
可以直接分配 C.prototype
作为其原型。在这种情况下,如果您的代码从 x
读取 C
的 私有字段,它仍然会失败
class C {
#value = "foo";
static getValue(x) {
return x.#value;
}
}
const x = { __proto__: C.prototype };
if (x instanceof C) {
console.log(C.getValue(x)); // TypeError: Cannot read private member #value from an object whose class did not declare it
}
为了避免这种情况,您可以通过向 C
添加 Symbol.hasInstance
方法来覆盖 instanceof
的行为,以便它使用 in
进行品牌检查
class C {
#value = "foo";
static [Symbol.hasInstance](x) {
return #value in x;
}
static getValue(x) {
return x.#value;
}
}
const x = { __proto__: C.prototype };
if (x instanceof C) {
// Doesn't run, because x is not a C
console.log(C.getValue(x));
}
请注意,您可能希望将此行为限制在当前类中;否则,它可能会导致子类的误报
class D extends C {}
console.log(new C() instanceof D); // true; because D inherits [Symbol.hasInstance] from C
您可以通过检查 this
是否是当前构造函数来做到这一点
class C {
#value = "foo";
static [Symbol.hasInstance](x) {
return this === C && #value in x;
}
}
class D extends C {}
console.log(new C() instanceof D); // false
console.log(new C() instanceof C); // true
console.log({ __proto__: C.prototype } instanceof C); // false
规范
规范 |
---|
ECMAScript 语言规范 # sec-relational-operators |
浏览器兼容性
BCD 表格仅在浏览器中加载