instanceof
instanceof 運算子用於檢測建構函式的 prototype 屬性是否出現在某個物件的原型鏈中的任何位置。返回值是一個布林值。其行為可以透過 Symbol.hasInstance 進行自定義。
試一試
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car("Honda", "Accord", 1998);
console.log(auto instanceof Car);
// Expected output: true
console.log(auto instanceof Object);
// Expected output: true
語法
object instanceof constructor
引數
object-
要測試的物件。
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() 安全地檢查給定物件是否確實是一個 Array,而無需關心它來自哪個領域。
例如,要在不同上下文中檢查 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 與 Map 一起使用
以下示例展示了 instanceof 與 Map 物件的行為。
const myMap = new Map();
myMap instanceof Map; // true
myMap instanceof Object; // true
myMap 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® 2026 語言規範 # sec-relational-operators |
瀏覽器相容性
載入中…