in
如果指定的属性位于指定对象或其原型链中,则 in
运算符返回 true
。
¥The in
operator returns true
if the specified property is in the specified object or its prototype chain.
in
运算符不能用于搜索其他集合中的值。要测试数组中是否存在某个值,请使用 Array.prototype.includes()
。对于集合,请使用 Set.prototype.has()
。
¥The in
operator cannot be used to search for values in other collections. To test if a certain value exists in an array, use Array.prototype.includes()
. For sets, use Set.prototype.has()
.
Try it
语法
参数
例外情况
描述
¥Description
in
运算符测试对象或其原型链中是否存在字符串或符号属性。如果你只想检查非继承属性,请改用 Object.hasOwn()
。
¥The in
operator tests if a string or symbol property is present in an object or its prototype chain. If you want to check for only non-inherited properties, use Object.hasOwn()
instead.
属性可能存在于对象中,但具有值 undefined
。因此,x in obj
与 obj.x !== undefined
不同。要在添加属性后使 in
返回 false
,请使用 delete
运算符,而不是将该属性的值设置为 undefined
。
¥A property may be present in an object but have value undefined
. Therefore, x in obj
is not the same as obj.x !== undefined
. To make in
return false
after a property is added, use the delete
operator instead of setting that property's value to undefined
.
你还可以使用 in
运算符来检查对象中是否已定义特定的 私有类字段或方法。如果定义了该属性,则该运算符返回 true
,否则返回 false
。这称为品牌检查,因为当且仅当对象是使用该类构造函数创建时,它才会返回 true
,之后你也可以安全地访问其他私有属性。
¥You can also use the in
operator to check whether a particular private class field or method has been defined in an object. The operator returns true
if the property is defined, and false
otherwise. This is known as a branded check, because it returns true
if and only if the object was created with that class constructor, after which you can safely access other private properties as well.
这是一种特殊的语法 - in
运算符的左侧是属性标识符而不是表达式,但不带引号(因为否则它是字符串属性,而不是私有属性)。
¥This is a special syntax — the left-hand side of the in
operator is a property identifier instead of an expression, but unquoted (because otherwise it's a string property, not a private property).
由于访问与当前类无关的对象上的私有属性会抛出 TypeError
而不是返回 undefined
,因此此语法允许你缩短:
¥Because accessing private properties on objects unrelated to the current class throws a TypeError
instead of returning undefined
, this syntax allows you to shorten:
class C {
#x;
static isC(obj) {
try {
obj.#x;
return true;
} catch {
return false;
}
}
}
到:
¥To:
class C {
#x;
static isC(obj) {
return #x in obj;
}
}
它通常还避免了仅仅为了访问可能不存在的私有属性而进行错误处理的需要。
¥It also generally avoids the need for dealing with error handling just to access a private property that may be nonexistent.
但是,in
运算符仍然要求在封闭类中事先声明私有属性 - 否则,它将抛出 SyntaxError
("私有字段 '#X' 必须在封闭类中声明"),与尝试访问未声明的私有属性时的情况相同。
¥However, the in
operator still requires the private property to be declared beforehand in the enclosing class — otherwise, it would throw a SyntaxError
("Private field '#x' must be declared in an enclosing class"), the same one as when you try to access an undeclared private property.
class C {
foo() {
#x in this;
}
}
new C().foo(); // SyntaxError: Private field '#x' must be declared in an enclosing class
示例
基本用法
¥Basic usage
以下示例显示了 in
运算符的一些用法。
¥The following examples show some uses of the in
operator.
// 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
构造函数创建的字符串,但不能指定字符串文字。
¥You must specify an object on the right side of the in
operator. For example, you can specify a string created with the String
constructor, but you cannot specify a string literal.
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 运算符
¥Using the in operator with deleted or undefined properties
如果使用 delete
运算符删除属性,则 in
运算符会返回该属性的 false
。
¥If you delete a property with the delete
operator, the in
operator returns false
for that property.
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。
¥If you set a property to undefined
but do not delete it, the in
operator returns true for that property.
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
。
¥The in
operator will return false
for empty array slots, even if accessing it directly returns undefined
.
const empties = new Array(3);
empties[2]; // returns undefined
2 in empties; // returns false
为了避免这种情况,请确保新数组始终填充非空值,或者不要写入超出数组末尾的索引。
¥To avoid this, make sure a new array is always filled with non-empty values or not write to indexes past the end of array.
const empties = new Array(3).fill(undefined);
2 in empties; // returns true
继承属性
¥Inherited properties
in
运算符为原型链中的属性返回 true
。如果你使用对象来存储任意键值对,这可能是不可取的。
¥The in
operator returns true
for properties in the prototype chain. This may be undesirable if you are using objects to store arbitrary key-value pairs.
const ages = { alice: 18, bob: 27 };
function hasPerson(name) {
return name in ages;
}
hasPerson("hasOwnProperty"); // true
你可以使用 Object.hasOwn()
来检查对象是否具有密钥。
¥You can use Object.hasOwn()
to check if the object has the key.
const ages = { alice: 18, bob: 27 };
function hasPerson(name) {
return Object.hasOwn(ages, name);
}
hasPerson("hasOwnProperty"); // false
或者,你应该考虑使用 空原型对象 或 Map
来存储 ages
,以避免其他错误。
¥Alternatively, you should consider using a null prototype object or a Map
for storing ages
, to avoid other bugs.
const ages = new Map([
["alice", 18],
["bob", 27],
]);
function hasPerson(name) {
return ages.has(name);
}
hasPerson("hasOwnProperty"); // false
使用 in 运算符实现品牌检查
¥Using the in operator to implement branded checks
下面的代码片段演示了一个静态函数,该函数告知对象是否是使用 Person
构造函数创建的,因此可以安全地执行其他方法。
¥The code fragment below demonstrates a static function that tells if an object was created with the Person
constructor and therefore can perform other methods safely.
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
}
它有助于防止以下情况:
¥It helps to prevent the following case:
const p2 = {};
p1.ageDifference(p2); // TypeError: Cannot read private member #age from an object whose class did not declare it
如果没有 in
运算符,你将必须使用 try...catch
块来检查对象是否具有私有属性。
¥Without the in
operator, you would have to use a try...catch
block to check if the object has the private property.
你还可以将其实现为类的 [Symbol.hasInstance]()
方法,以便可以使用 instanceof
运算符执行相同的检查(默认情况下,仅检查对象原型链中是否存在 Person.prototype
)。
¥You can also implement this as a [Symbol.hasInstance]()
method of the class, so that you can use the instanceof
operator to perform the same check (which, by default, only checks for the existence of Person.prototype
in the object's prototype chain).
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
}
¥For more examples, see Private properties and the class guide.
规范
Specification |
---|
ECMAScript Language Specification # sec-relational-operators |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also