in

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

in 運算子用於判斷指定的屬性是否在指定的物件或其原型鏈中,如果在則返回 true

in 運算子不能用於在其他集合中搜索值。要測試某個值是否存在於陣列中,請使用 Array.prototype.includes()。對於 Set,請使用 Set.prototype.has()

試一試

const car = { make: "Honda", model: "Accord", year: 1998 };

console.log("make" in car);
// Expected output: true

delete car.make;
if ("make" in car === false) {
  car.make = "Suzuki";
}

console.log(car.make);
// Expected output: "Suzuki"

語法

js
prop in object
#prop in object

引數

prop

表示屬性名稱的字串或 Symbol(非 Symbol 將被強制轉換為字串)。也可以是私有元素識別符號

object

用於檢查其(或其原型鏈)是否包含具有指定名稱(prop)的屬性的物件。

異常

TypeError

如果 object 不是物件(即原始值),則丟擲此錯誤。

描述

in 運算子測試字串或 Symbol 屬性是否存在於物件或其原型鏈中。如果你只想檢查非繼承屬性,請改用 Object.hasOwn()

屬性可能存在於物件中,但其值為 undefined。因此,"x" in objobj.x !== undefined 不同。要在新增屬性後使 in 返回 false,請使用 delete 運算子而不是將該屬性的值設定為 undefined

你還可以使用 in 運算子檢查物件中是否定義了特定的私有類欄位或方法。如果屬性已定義,則該運算子返回 true,否則返回 false。這被稱為品牌檢查,因為它僅當物件是用該類建構函式建立時才返回 true,之後你也可以安全地訪問其他私有元素。

這是一種特殊的語法——in 運算子的左側是屬性識別符號而不是表示式,但是沒有引號(因為否則它將是一個字串屬性,而不是私有元素)。

因為訪問與當前類無關的物件的私有元素會丟擲 TypeError 而不是返回 undefined,所以此語法允許你縮短

js
class C {
  #x;
  static isC(obj) {
    try {
      obj.#x;
      return true;
    } catch {
      return false;
    }
  }
}

js
class C {
  #x;
  static isC(obj) {
    return #x in obj;
  }
}

它通常也避免了為了訪問可能不存在的私有元素而需要處理錯誤。

然而,in 運算子仍然要求私有元素在封閉類中事先宣告——否則,它會丟擲 SyntaxError(“私有欄位 '#x' 必須在封閉類中宣告”),與你嘗試訪問未宣告的私有元素時丟擲的錯誤相同。

js
class C {
  foo() {
    #x in this;
  }
}

new C().foo(); // SyntaxError: Private field '#x' must be declared in an enclosing class

示例

基本用法

以下示例展示了 in 運算子的一些用法。

js
// Arrays
const trees = ["redwood", "bay", "cedar", "oak", "maple"];
0 in trees; // returns true
3 in trees; // returns true
6 in trees; // returns false
"bay" in trees; // returns false (you must specify the index number, not the value at that index)
"length" in trees; // returns true (length is an Array property)
Symbol.iterator in trees; // returns true

// Predefined objects
"PI" in Math; // returns true

// Custom objects
const myCar = { make: "Honda", model: "Accord", year: 1998 };
"make" in myCar; // returns true
"model" in myCar; // returns true

你必須在 in 運算子的右側指定一個物件。例如,你可以指定用 String 建構函式建立的字串,但不能指定字串字面量。

js
const color1 = new String("green");
"length" in color1; // returns true

const color2 = "coral";
// generates an error (color2 is not a String object)
"length" in color2;

使用 in 運算子與已刪除或未定義屬性

如果你使用 delete 運算子刪除一個屬性,則 in 運算子對該屬性返回 false

js
const myCar = { make: "Honda", model: "Accord", year: 1998 };
delete myCar.make;
"make" in myCar; // returns false

const trees = ["redwood", "bay", "cedar", "oak", "maple"];
delete trees[3];
3 in trees; // returns false

如果你將一個屬性設定為 undefined 但未刪除它,則 in 運算子對該屬性返回 true。

js
const myCar = { make: "Honda", model: "Accord", year: 1998 };
myCar.make = undefined;
"make" in myCar; // returns true
js
const trees = ["redwood", "bay", "cedar", "oak", "maple"];
trees[3] = undefined;
3 in trees; // returns true

即使直接訪問返回 undefinedin 運算子也會對空陣列槽返回 false

js
const empties = new Array(3);
empties[2]; // returns undefined
2 in empties; // returns false

為避免這種情況,請確保新陣列始終填充非空值或不寫入超出陣列末尾的索引。

js
const empties = new Array(3).fill(undefined);
2 in empties; // returns true

繼承屬性

in 運算子對原型鏈中的屬性返回 true。如果你使用物件儲存任意鍵值對,這可能是不受歡迎的。

js
const ages = { alice: 18, bob: 27 };

function hasPerson(name) {
  return name in ages;
}

hasPerson("hasOwnProperty"); // true

你可以使用 Object.hasOwn() 檢查物件是否具有該鍵。

js
const ages = { alice: 18, bob: 27 };

function hasPerson(name) {
  return Object.hasOwn(ages, name);
}

hasPerson("hasOwnProperty"); // false

或者,你應該考慮使用空原型物件Map 來儲存 ages,以避免其他錯誤。

js
const ages = new Map([
  ["alice", 18],
  ["bob", 27],
]);

function hasPerson(name) {
  return ages.has(name);
}

hasPerson("hasOwnProperty"); // false

使用 in 運算子實現品牌檢查

下面的程式碼片段演示了一個靜態函式,該函式指示物件是否是用 Person 建構函式建立的,因此可以安全地執行其他方法。

js
class Person {
  #age;
  constructor(age) {
    this.#age = age;
  }
  static isPerson(o) {
    return #age in o;
  }
  ageDifference(other) {
    return this.#age - other.#age;
  }
}

const p1 = new Person(20);
const p2 = new Person(30);
console.log(p1.ageDifference(p2)); // -10
console.log(Person.isPerson(p1)); // true

if (Person.isPerson(p1) && Person.isPerson(p2)) {
  console.log(p1.ageDifference(p2)); // -10
}

它有助於防止以下情況

js
const p2 = {};

p1.ageDifference(p2); // TypeError: Cannot read private member #age from an object whose class did not declare it

如果沒有 in 運算子,你將不得不使用 try...catch 塊來檢查物件是否具有私有元素。

你也可以將其實現為類的 [Symbol.hasInstance]() 方法,這樣你就可以使用 instanceof 運算子執行相同的檢查(預設情況下,它只檢查物件原型鏈中是否存在 Person.prototype)。

js
class Person {
  #age;
  constructor(age) {
    this.#age = age;
  }
  static [Symbol.hasInstance](o) {
    // Testing `this` to prevent false-positives when
    // calling `instanceof SubclassOfPerson`
    return this === Person && #age in o;
  }
  ageDifference(other) {
    return this.#age - other.#age;
  }
}

const p1 = new Person(20);
const p2 = new Person(30);

if (p1 instanceof Person && p2 instanceof Person) {
  console.log(p1.ageDifference(p2)); // -10
}

有關更多示例,請參閱私有元素類指南

規範

規範
ECMAScript® 2026 語言規範
# sec-relational-operators

瀏覽器相容性

另見