in
in
运算符如果指定的属性在指定对象或其原型链中,则返回 true
。
in
运算符不能用于在其他集合中搜索值。要测试某个值是否在数组中存在,请使用 Array.prototype.includes()
。对于集合,请使用 Set.prototype.has()
。
试一试
语法
prop in object
#prop in object
参数
异常
TypeError
-
如果
object
不是对象(即原始值),则抛出。
描述
in
运算符测试字符串或符号属性是否存在于对象或其原型链中。如果只想检查非继承属性,请改用 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
in
运算符将为 空数组插槽 返回 false
,即使直接访问它返回 undefined
。
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 语言规范 # sec-relational-operators |
浏览器兼容性
BCD 表格仅在浏览器中加载