A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for...in below:

for...in - JavaScript | MDN

for...in

Baseline Widely available

for...in 语句迭代一个对象的所有可枚举字符串属性(除 Symbol 以外),包括继承的可枚举属性。

尝试一下
const object = { a: 1, b: 2, c: 3 };

for (const property in object) {
  console.log(`${property}: ${object[property]}`);
}

// Expected output:
// "a: 1"
// "b: 2"
// "c: 3"
语法
for (variable in object)
  statement
参数
variable

在每次迭代时接收一个字符串属性名。它可以通过使用 const、let 或 var 进行声明,也可以是一个赋值目标(例如,先前声明的变量、对象属性或解构模式)。使用 var 声明的变量不会局限于循环内部,即它们与 for...in 循环所在的作用域相同。

object

被迭代非符号可枚举属性的对象。

statement

每次迭代后执行的语句。可以引用 variable。可以使用块语句执行多个语句。

描述

该循环将迭代对象本身的所有可枚举属性,以及对象从其原型链继承的属性(原型链中较近的原型的属性优先于较远的原型的属性)。

for...in 循环只会迭代可枚举的非符号属性。从内置构造函数(如 Array 和 Object)创建的对象会从 Array.prototype 和 Object.prototype 继承不可枚举属性,例如 Array 的 indexOf() 方法或 Object 的 toString() 方法,它们在 for...in 循环中不会被访问到。

根据现代 ECMAScript 规范的定义,遍历的顺序是一致且可预测的。在原型链的每个组件中,所有非负整数键(可以作为数组索引)将首先按值升序遍历,然后是其他字符串键按属性创建的先后顺序升序遍历。

在 for...in 循环中,variable 部分可以接受任何在 = 运算符之前的内容。只要在循环体内部不重新赋值(可以在迭代之间更改,因为它们是两个独立的变量),你可以使用 const 来声明变量。否则,你可以使用 let。你可以使用解构来为多个局部变量赋值,或者使用属性访问器(例如 for (x.y in iterable))将值赋给对象属性。

一种遗留的语法允许在 for...in 循环中的 var 声明的循环变量具有初始值。在严格模式下,这会抛出语法错误,而在非严格模式下则会被忽略。

删除、添加或修改的属性

for...in 按以下方式访问属性键:

  1. 它首先获取当前对象的所有自有的字符串键,其方式与 Object.getOwnPropertyNames() 非常相似。
  2. 对于每一个键,如果没有访问过具有相同值的字符串,则获取属性描述符并只访问可枚举的属性。但是,即使该属性不可枚举,也会标记为已访问。
  3. 然后,当前对象被替换为其原型,并重复上述过程。

这意味着:

一般来说,最好不要在迭代过程中添加、修改或删除对象属性,除非是正在访问的属性。规范明确允许实现可以在以下情况下不遵循上述算法:

在这些情况下,实现可能与你期望的行为不同,甚至可能与其他实现不同。

数组迭代和 for...in

数组索引只是具有整数名称的可枚举属性,除此之外与一般对象属性完全相同。for...in 循环将在遍历其他键之前遍历所有整数键,并且按照严格递增的顺序进行,使得 for...in 的行为接近正常的数组迭代。然而,for...in 循环会返回所有可枚举属性,包括那些具有非整数名称和被继承的属性。与 for...of 不同,for...in 使用属性枚举而不是数组的迭代器。在稀疏数组中,for...of 会访问空槽,但 for...in 不会访问空槽。

最好使用带有数值索引的 for 循环、Array.prototype.forEach() 或 for...of 循环,因为它们会将索引作为数字而不是字符串返回,并且还会避免非索引属性的干扰。

仅迭代自身的属性

如果你只想迭代对象本身的属性,而不是它的原型,你可以使用以下技术之一:

Object.keys 会返回一个包含所有可枚举的自有字符串属性的数组,而 Object.getOwnPropertyNames 则会包含所有属性,包括不可枚举的。

许多 JavaScript 风格指南和代码检查工具建议避免使用 for...in 循环,因为它会遍历整个原型链,这很少是我们想要的,并且可能会与更常用的 for...of 循环混淆。for...in 循环最常用于调试目的,它是一种简单的方式来检查对象的属性(通过向控制台输出或其他方式)。在对象被用作临时键值对的情况下,for...in 循环可以检查这些键中是否存在持有特定值的键。

示例 使用 for ... in

下面的 for...in 循环迭代对象所有可枚举的非符号属性,并输出属性名和对应值的字符串。

const obj = { a: 1, b: 2, c: 3 };

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

// 输出:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
迭代自有属性

下面的函数展示了 Object.hasOwn() 的用法:继承的属性不会显示。

const triangle = { a: 1, b: 2, c: 3 };

function ColoredTriangle() {
  this.color = "红色";
}

ColoredTriangle.prototype = triangle;

const obj = new ColoredTriangle();

for (const prop in obj) {
  if (Object.hasOwn(obj, prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  }
}

// 输出:
// "obj.color = 红色"
并发修改

警告: 你不应该自己编写类似的代码。这里仅仅展示了 for...in 在某些极端情况下的行为。

在迭代期间添加到当前对象的属性永远不会被访问:

const obj = { a: 1, b: 2 };

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
  obj.c = 3;
}

// 输出:
// obj.a = 1
// obj.b = 2

被遮蔽(shadowed)的属性只会被访问一次:

const proto = { a: 1 };
const obj = { __proto__: proto, a: 2 };

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

// 输出:
// obj.a = 2

Object.defineProperty(obj, "a", { enumerable: false });

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}
// 没有输出,因为第一个“a”属性已经被访问过,并且是不可枚举的。

此外,请考虑以下情况,即行为是未指定的,并且实现往往偏离规定的算法:

在迭代过程中更改原型链:

const obj = { a: 1, b: 2 };

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
  Object.setPrototypeOf(obj, { c: 3 });
}

在迭代过程中删除属性:

const obj = { a: 1, b: 2, c: 3 };

// 在属性被访问前删除它
for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
  delete obj.c;
}

const obj2 = { a: 1, b: 2, c: 3 };

// 在属性被访问后删除它
for (const prop in obj2) {
  console.log(`obj2.${prop} = ${obj2[prop]}`);
  delete obj2.a;
}

在迭代过程中向原型链添加可枚举属性:

const proto = {};
const obj = { __proto__: proto, a: 1, b: 2 };

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
  proto.c = 3;
}

在迭代过程中修改属性的可枚举性:

const obj = { a: 1, b: 2, c: 3 };

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
  Object.defineProperty(obj, "c", { enumerable: false });
}
规范 浏览器兼容性 参见

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4