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 |
浏览器兼容性
加载中…