instanceof

instanceof 运算符测试以查看构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。返回值是一个布尔值。它的行为可以通过 Symbol.hasInstance 自定义。

试试看

语法

js
object instanceof constructor

参数

对象

要测试的对象。

constructor

要测试的构造函数。

异常

TypeError

如果 constructor 不是对象,则抛出。如果 constructor 没有 [Symbol.hasInstance]() 方法,它也必须是一个函数。

描述

instanceof 运算符测试 constructor.prototype 是否存在于 object 的原型链中。这通常(尽管并非总是如此)意味着 object 是用 constructor 构造的。

js
// 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 属性。

js
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

js
class Base {}
const BoundBase = Base.bind(null, 1, 2);
console.log(new Base() instanceof BoundBase); // true

instanceof 和 Symbol.hasInstance

如果 constructorSymbol.hasInstance 方法,则该方法将优先调用,并将 object 作为其唯一参数,并将 constructor 作为 this

js
// 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 一起使用

以下示例显示了 instanceofString 对象的行为。

js
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 一起使用

以下示例显示了 instanceofDate 对象的行为。

js
const myDate = new Date();

myDate instanceof Date; // true
myDate instanceof Object; // true
myDate instanceof String; // false

使用 Object.create() 创建的对象

以下示例显示了 instanceof 与使用 Object.create() 创建的对象的行为。

js
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 对象类型和该对象类型的实例 mycarinstanceof 运算符演示了 mycar 对象是 Car 类型和 Object 类型。

js
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,您可以执行

js
if (!(mycar instanceof Car)) {
  // Do something, like:
  // mycar = new Car(mycar)
}

这与

js
if (!mycar instanceof Car) {
  // unreachable code
}

这将始终为 false。(!mycar 将在 instanceof 之前进行评估,因此您始终尝试了解布尔值是否为 Car 的实例)。

覆盖 instanceof 的行为

使用 instanceof 的一个常见陷阱是相信如果 x instanceof C,那么 x 是使用 C 作为构造函数创建的。这不是真的,因为 x 可以直接分配 C.prototype 作为其原型。在这种情况下,如果您的代码从 x 读取 C私有字段,它仍然会失败

js
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 进行品牌检查

js
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));
}

请注意,您可能希望将此行为限制在当前类中;否则,它可能会导致子类的误报

js
class D extends C {}
console.log(new C() instanceof D); // true; because D inherits [Symbol.hasInstance] from C

您可以通过检查 this 是否是当前构造函数来做到这一点

js
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 表格仅在浏览器中加载

另请参见