instanceof
instanceof
运算符测试构造函数的 prototype
属性是否出现在对象原型链中的任何位置。返回值是一个布尔值。可以使用 Symbol.hasInstance
自定义其行为。
¥The instanceof
operator tests to see if the prototype
property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value. Its behavior can be customized with Symbol.hasInstance
.
Try it
语法
参数
例外情况
¥Exceptions
TypeError
-
如果
constructor
不是对象,则抛出该异常。如果constructor
没有[Symbol.hasInstance]()
方法,那么它也必须是一个函数。
描述
¥Description
instanceof
运算符测试 constructor.prototype
在 object
原型链中的存在。这通常(尽管 不总是)意味着 object
是用 constructor
构建的。
¥The instanceof
operator tests the presence of constructor.prototype
in object
's prototype chain. This usually (though not always) means object
was constructed with 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
的原型来改变。
¥Note that the value of an instanceof
test can change if constructor.prototype
is re-assigned after creating the object (which is usually discouraged). It can also be changed by changing object
's prototype using Object.setPrototypeOf
.
类的行为方式相同,因为类也具有 prototype
属性。
¥Classes behave in the same way, because classes also have the prototype
property.
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
。
¥For bound functions, instanceof
looks up for the prototype
property on the target function, since bound functions don't have prototype
.
class Base {}
const BoundBase = Base.bind(null, 1, 2);
console.log(new Base() instanceof BoundBase); // true
instanceof 和 Symbol.hasInstance
¥instanceof and Symbol.hasInstance
如果 constructor
有 Symbol.hasInstance
方法,则优先调用该方法,以 object
作为其唯一参数,以 constructor
作为 this
。
¥If constructor
has a Symbol.hasInstance
method, the method will be called in priority, with object
as its only argument and constructor
as 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
页面。
¥Because all functions inherit from Function.prototype
by default, most of the time, the Function.prototype[Symbol.hasInstance]()
method specifies the behavior of instanceof
when the right-hand side is a function. See the Symbol.hasInstance
page for the exact algorithm of instanceof
.
instanceof 和多个字段
¥instanceof and multiple realms
JavaScript 执行环境(窗口、框架等)各有其自己的字段。这意味着它们有不同的内置函数(不同的全局对象、不同的构造函数等)。这可能会导致意想不到的结果。例如,[] instanceof window.frames[0].Array
将返回 false
,因为当前字段中的 Array.prototype !== window.frames[0].Array.prototype
和数组继承自前者。
¥JavaScript execution environments (windows, frames, etc.) are each in their own realm. This means that they have different built-ins (different global object, different constructors, etc.). This may result in unexpected results. For instance, [] instanceof window.frames[0].Array
will return false
, because Array.prototype !== window.frames[0].Array.prototype
and arrays in the current realm inherit from the former.
一开始这可能没有意义,但对于处理多个框架或窗口的脚本,以及通过函数将对象从一个上下文传递到另一个上下文,这将是一个有效且强大的问题。例如,你可以使用 Array.isArray()
安全地检查给定对象是否实际上是一个数组,而忽略它来自哪个字段。
¥This may not make sense at first, but for scripts dealing with multiple frames or windows, and passing objects from one context to another via functions, this will be a valid and strong issue. For instance, you can securely check if a given object is in fact an Array using Array.isArray()
, neglecting which realm it comes from.
例如,要检查 Node
在不同上下文中是否是 SVGElement
,可以使用 myNode instanceof myNode.ownerDocument.defaultView.SVGElement
。
¥For example, to check if a Node
is an SVGElement
in a different context, you can use myNode instanceof myNode.ownerDocument.defaultView.SVGElement
.
示例
将 instanceof 与字符串一起使用
¥Using instanceof with String
以下示例显示了 instanceof
与 String
对象的行为。
¥The following example shows the behavior of instanceof
with String
objects.
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 与日期一起使用
使用 Object.create() 创建的对象
¥Objects created using Object.create()
以下示例显示了 instanceof
与使用 Object.create()
创建的对象的行为。
¥The following example shows the behavior of instanceof
with objects created using 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 类型
¥Demonstrating that mycar is of type Car and type Object
以下代码创建对象类型 Car
和该对象类型 mycar
的实例。instanceof
运算符表明 mycar
对象的类型为 Car
且类型为 Object
。
¥The following code creates an object type Car
and an instance of that object type, mycar
. The instanceof
operator demonstrates that the mycar
object is of type Car
and of type 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
不是一个实例
¥Not an instanceof
要测试对象是否不是 instanceof
特定构造函数,你可以执行以下操作:
¥To test if an object is not an instanceof
a specific constructor, you can do:
if (!(mycar instanceof Car)) {
// Do something, like:
// mycar = new Car(mycar)
}
这确实不同于:
¥This is really different from:
if (!mycar instanceof Car) {
// unreachable code
}
这将永远是 false
。(!mycar
将在 instanceof
之前计算,因此你总是尝试知道布尔值是否是 Car
的实例)。
¥This will always be false
. (!mycar
will be evaluated before instanceof
, so you always try to know if a boolean is an instance of Car
).
覆盖 instanceof 的行为
¥Overriding the behavior of instanceof
使用 instanceof
的一个常见陷阱是相信,如果 x instanceof C
,那么 x
是使用 C
作为构造函数创建的。这是不正确的,因为 x
可以直接用 C.prototype
作为其原型来赋值。在这种情况下,如果你的代码从 x
读取 私有字段 of C
,它仍然会失败:
¥A common pitfall of using instanceof
is believing that, if x instanceof C
, then x
was created using C
as constructor. This is not true, because x
could be directly assigned with C.prototype
as its prototype. In this case, if your code reads private fields of C
from x
, it would still fail:
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
进行品牌检查:
¥To avoid this, you can override the behavior of instanceof
by adding a Symbol.hasInstance
method to C
, so that it does a branded check with 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));
}
请注意,你可能希望将此行为限制为当前类;否则,可能会导致子类出现误报:
¥Note that you may want to limit this behavior to the current class; otherwise, it could lead to false positives for subclasses:
class D extends C {}
console.log(new C() instanceof D); // true; because D inherits [Symbol.hasInstance] from C
你可以通过检查 this
是否是当前构造函数来做到这一点:
¥You could do this by checking that this
is the current constructor:
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
规范
Specification |
---|
ECMAScript Language Specification # sec-relational-operators |
浏览器兼容性
BCD tables only load in the browser