in

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

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"

语法

js
prop in object
#prop in object

参数

prop

表示属性名称的字符串或 Symbol(非 Symbol 将被强制转换为字符串)。也可以是私有元素标识符

object

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

异常

TypeError

如果 object 不是对象(即原始值),则抛出此错误。

描述

in 运算符测试字符串或 Symbol 属性是否存在于对象或其原型链中。如果你只想检查非继承属性,请改用 Object.hasOwn()

属性可能存在于对象中,但其值为 undefined。因此,"x" in objobj.x !== undefined 不同。要在添加属性后使 in 返回 false,请使用 delete 运算符而不是将该属性的值设置为 undefined

你还可以使用 in 运算符检查对象中是否定义了特定的私有类字段或方法。如果属性已定义,则该运算符返回 true,否则返回 false。这被称为品牌检查,因为它仅当对象是用该类构造函数创建时才返回 true,之后你也可以安全地访问其他私有元素。

这是一种特殊的语法——in 运算符的左侧是属性标识符而不是表达式,但是没有引号(因为否则它将是一个字符串属性,而不是私有元素)。

因为访问与当前类无关的对象的私有元素会抛出 TypeError 而不是返回 undefined,所以此语法允许你缩短

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

js
class C {
  #x;
  static isC(obj) {
    return #x in obj;
  }
}

它通常也避免了为了访问可能不存在的私有元素而需要处理错误。

然而,in 运算符仍然要求私有元素在封闭类中事先声明——否则,它会抛出 SyntaxError(“私有字段 '#x' 必须在封闭类中声明”),与你尝试访问未声明的私有元素时抛出的错误相同。

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

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

示例

基本用法

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

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

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 运算符与已删除或未定义属性

如果你使用 delete 运算符删除一个属性,则 in 运算符对该属性返回 false

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。

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

即使直接访问返回 undefinedin 运算符也会对空数组槽返回 false

js
const empties = new Array(3);
empties[2]; // returns undefined
2 in empties; // returns false

为避免这种情况,请确保新数组始终填充非空值或不写入超出数组末尾的索引。

js
const empties = new Array(3).fill(undefined);
2 in empties; // returns true

继承属性

in 运算符对原型链中的属性返回 true。如果你使用对象存储任意键值对,这可能是不受欢迎的。

js
const ages = { alice: 18, bob: 27 };

function hasPerson(name) {
  return name in ages;
}

hasPerson("hasOwnProperty"); // true

你可以使用 Object.hasOwn() 检查对象是否具有该键。

js
const ages = { alice: 18, bob: 27 };

function hasPerson(name) {
  return Object.hasOwn(ages, name);
}

hasPerson("hasOwnProperty"); // false

或者,你应该考虑使用空原型对象Map 来存储 ages,以避免其他错误。

js
const ages = new Map([
  ["alice", 18],
  ["bob", 27],
]);

function hasPerson(name) {
  return ages.has(name);
}

hasPerson("hasOwnProperty"); // false

使用 in 运算符实现品牌检查

下面的代码片段演示了一个静态函数,该函数指示对象是否是用 Person 构造函数创建的,因此可以安全地执行其他方法。

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
}

它有助于防止以下情况

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

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
}

有关更多示例,请参阅私有元素类指南

规范

规范
ECMAScript® 2026 语言规范
# sec-relational-operators

浏览器兼容性

另见