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

语法

¥Syntax

js
prop in object
#prop in object

参数

¥Parameters

prop

表示属性名称的字符串或符号(非符号将为 强制为字符串)。也可以是 私有属性标识符

object

检查它(或其原型链)是否包含指定名称(prop)的属性的对象。

例外情况

¥Exceptions

TypeError

如果 object 不是对象(即基元),则抛出该异常。

描述

¥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 objobj.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:

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

到:

¥To:

js
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.

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

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

示例

¥Examples

基本用法

¥Basic usage

以下示例显示了 in 运算符的一些用法。

¥The following examples show some uses of the in operator.

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 构造函数创建的字符串,但不能指定字符串文字。

¥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.

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 运算符

¥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.

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。

¥If you set a property to undefined but do not delete it, the in operator returns true for that property.

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

in 运算符将为 空数组槽 返回 false,即使直接访问它也会返回 undefined

¥The in operator will return false for empty array slots, even if accessing it directly returns undefined.

js
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.

js
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.

js
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.

js
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.

js
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.

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
}

它有助于防止以下情况:

¥It helps to prevent the following case:

js
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).

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
}

有关更多示例,请参阅 私有属性班主任

¥For more examples, see Private properties and the class guide.

规范

Specification
ECMAScript Language Specification
# sec-relational-operators

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看