in
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"
語法
prop in object
#prop in object
引數
異常
TypeError-
如果
object不是物件(即原始值),則丟擲此錯誤。
描述
in 運算子測試字串或 Symbol 屬性是否存在於物件或其原型鏈中。如果你只想檢查非繼承屬性,請改用 Object.hasOwn()。
屬性可能存在於物件中,但其值為 undefined。因此,"x" in obj 與 obj.x !== undefined 不同。要在新增屬性後使 in 返回 false,請使用 delete 運算子而不是將該屬性的值設定為 undefined。
你還可以使用 in 運算子檢查物件中是否定義了特定的私有類欄位或方法。如果屬性已定義,則該運算子返回 true,否則返回 false。這被稱為品牌檢查,因為它僅當物件是用該類建構函式建立時才返回 true,之後你也可以安全地訪問其他私有元素。
這是一種特殊的語法——in 運算子的左側是屬性識別符號而不是表示式,但是沒有引號(因為否則它將是一個字串屬性,而不是私有元素)。
因為訪問與當前類無關的物件的私有元素會丟擲 TypeError 而不是返回 undefined,所以此語法允許你縮短
class C {
#x;
static isC(obj) {
try {
obj.#x;
return true;
} catch {
return false;
}
}
}
至
class C {
#x;
static isC(obj) {
return #x in obj;
}
}
它通常也避免了為了訪問可能不存在的私有元素而需要處理錯誤。
然而,in 運算子仍然要求私有元素在封閉類中事先宣告——否則,它會丟擲 SyntaxError(“私有欄位 '#x' 必須在封閉類中宣告”),與你嘗試訪問未宣告的私有元素時丟擲的錯誤相同。
class C {
foo() {
#x in this;
}
}
new C().foo(); // SyntaxError: Private field '#x' must be declared in an enclosing class
示例
基本用法
以下示例展示了 in 運算子的一些用法。
// 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 建構函式建立的字串,但不能指定字串字面量。
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。
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。
const myCar = { make: "Honda", model: "Accord", year: 1998 };
myCar.make = undefined;
"make" in myCar; // returns true
const trees = ["redwood", "bay", "cedar", "oak", "maple"];
trees[3] = undefined;
3 in trees; // returns true
即使直接訪問返回 undefined,in 運算子也會對空陣列槽返回 false。
const empties = new Array(3);
empties[2]; // returns undefined
2 in empties; // returns false
為避免這種情況,請確保新陣列始終填充非空值或不寫入超出陣列末尾的索引。
const empties = new Array(3).fill(undefined);
2 in empties; // returns true
繼承屬性
in 運算子對原型鏈中的屬性返回 true。如果你使用物件儲存任意鍵值對,這可能是不受歡迎的。
const ages = { alice: 18, bob: 27 };
function hasPerson(name) {
return name in ages;
}
hasPerson("hasOwnProperty"); // true
你可以使用 Object.hasOwn() 檢查物件是否具有該鍵。
const ages = { alice: 18, bob: 27 };
function hasPerson(name) {
return Object.hasOwn(ages, name);
}
hasPerson("hasOwnProperty"); // false
或者,你應該考慮使用空原型物件或 Map 來儲存 ages,以避免其他錯誤。
const ages = new Map([
["alice", 18],
["bob", 27],
]);
function hasPerson(name) {
return ages.has(name);
}
hasPerson("hasOwnProperty"); // false
使用 in 運算子實現品牌檢查
下面的程式碼片段演示了一個靜態函式,該函式指示物件是否是用 Person 建構函式建立的,因此可以安全地執行其他方法。
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
}
它有助於防止以下情況
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)。
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 |
瀏覽器相容性
載入中…