for...of
for...of
语句执行一个循环,该循环对源自 可迭代对象 的一系列值进行操作。可迭代对象包括内置实例,例如 Array
、String
、TypedArray
、Map
、Set
、NodeList
(和其他 DOM 集合),以及 arguments
对象、生成器函数 生成的 generators 和用户定义的可迭代对象。
¥The for...of
statement executes a loop that operates on a sequence of values sourced from an iterable object. Iterable objects include instances of built-ins such as Array
, String
, TypedArray
, Map
, Set
, NodeList
(and other DOM collections), as well as the arguments
object, generators produced by generator functions, and user-defined iterables.
Try it
语法
描述
¥Description
for...of
循环对源自可迭代对象的值按顺序进行一一操作。循环对值的每次操作称为迭代,并且循环被称为对可迭代对象进行迭代。每次迭代都会执行可能引用当前序列值的语句。
¥A for...of
loop operates on the values sourced from an iterable one by one in sequential order. Each operation of the loop on a value is called an iteration, and the loop is said to iterate over the iterable. Each iteration executes statements that may refer to the current sequence value.
当 for...of
循环迭代可迭代对象时,它首先调用可迭代对象的 [Symbol.iterator]()
方法,该方法返回 iterator,然后重复调用结果迭代器的 next()
方法以生成要分配给 variable
的值序列。
¥When a for...of
loop iterates over an iterable, it first calls the iterable's [Symbol.iterator]()
method, which returns an iterator, and then repeatedly calls the resulting iterator's next()
method to produce the sequence of values to be assigned to variable
.
当迭代器完成时,A for...of
循环退出(next()
结果是具有 done: true
的对象)。与其他循环语句一样,你可以在 statement
内使用 控制流语句:
¥A for...of
loop exits when the iterator has completed (the next()
result is an object with done: true
). Like other looping statements, you can use control flow statements inside statement
:
如果 for...of
循环提前退出(例如遇到 break
语句或抛出错误),则调用迭代器的 return()
方法来执行任何清理。
¥If the for...of
loop exited early (e.g. a break
statement is encountered or an error is thrown), the return()
method of the iterator is called to perform any cleanup.
for...of
的 variable
部分接受 =
运算符之前的任何内容。你可以使用 const
来声明变量,只要它不在循环体内重新分配即可(它可以在迭代之间更改,因为它们是两个单独的变量)。否则,你可以使用 let
。
¥The variable
part of for...of
accepts anything that can come before the =
operator. You can use const
to declare the variable as long as it's not reassigned within the loop body (it can change between iterations, because those are two separate variables). Otherwise, you can use let
.
const iterable = [10, 20, 30];
for (let value of iterable) {
value += 1;
console.log(value);
}
// 11
// 21
// 31
注意:每次迭代都会创建一个新变量。在循环体内重新分配变量不会影响可迭代对象(在本例中为数组)中的原始值。
¥Note: Each iteration creates a new variable. Reassigning the variable inside the loop body does not affect the original value in the iterable (an array, in this case).
你可以使用 destructuring 分配多个局部变量,或使用像 for (x.y of iterable)
这样的属性访问器将值分配给对象属性。
¥You can use destructuring to assign multiple local variables, or use a property accessor like for (x.y of iterable)
to assign the value to an object property.
但是,有一条特殊规则禁止使用 async
作为变量名。这是无效的语法:
¥However, a special rule forbids using async
as the variable name. This is invalid syntax:
let async;
for (async of [1, 2, 3]); // SyntaxError: The left-hand side of a for-of loop may not be 'async'.
这是为了避免有效代码 for (async of => {};;)
出现语法歧义,该代码是 for
循环。
¥This is to avoid syntax ambiguity with the valid code for (async of => {};;)
, which is a for
loop.
示例
迭代数组
迭代字符串
¥Iterating over a string
琴弦为 按 Unicode 代码点迭代。
¥Strings are iterated by Unicode code points.
const iterable = "boo";
for (const value of iterable) {
console.log(value);
}
// "b"
// "o"
// "o"
迭代 TypedArray
迭代 Map
迭代集合
迭代参数对象
迭代 NodeList
¥Iterating over a NodeList
以下示例通过迭代 NodeList
DOM 集合,将 read
类添加到作为 <article>
元素的直接后代的段落。
¥The following example adds a read
class to paragraphs that are direct descendants of the <article>
element by iterating over a NodeList
DOM collection.
const articleParagraphs = document.querySelectorAll("article > p");
for (const paragraph of articleParagraphs) {
paragraph.classList.add("read");
}
迭代用户定义的可迭代对象
¥Iterating over a user-defined iterable
使用返回自定义迭代器的 [Symbol.iterator]()
方法迭代对象:
¥Iterating over an object with an [Symbol.iterator]()
method that returns a custom iterator:
const iterable = {
[Symbol.iterator]() {
let i = 1;
return {
next() {
if (i <= 3) {
return { value: i++, done: false };
}
return { value: undefined, done: true };
},
};
},
};
for (const value of iterable) {
console.log(value);
}
// 1
// 2
// 3
使用 [Symbol.iterator]()
生成器方法迭代对象:
¥Iterating over an object with an [Symbol.iterator]()
generator method:
const iterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
},
};
for (const value of iterable) {
console.log(value);
}
// 1
// 2
// 3
可迭代迭代器(具有返回 this
的 [Symbol.iterator]()
方法的迭代器)是一种相当常见的技术,可以使迭代器在需要可迭代的语法(例如 for...of
)中使用。
¥Iterable iterators (iterators with a [Symbol.iterator]()
method that returns this
) are a fairly common technique to make iterators usable in syntaxes expecting iterables, such as for...of
.
let i = 1;
const iterator = {
next() {
if (i <= 3) {
return { value: i++, done: false };
}
return { value: undefined, done: true };
},
[Symbol.iterator]() {
return this;
},
};
for (const value of iterator) {
console.log(value);
}
// 1
// 2
// 3
迭代生成器
提早退出
¥Early exiting
在第一个循环中执行 break
语句会导致其提前退出。迭代器尚未完成,因此第二个循环将从第一个循环停止的地方继续。
¥Execution of the break
statement in the first loop causes it to exit early. The iterator is not finished yet, so the second loop will continue from where the first one stopped at.
const source = [1, 2, 3];
const iterator = source[Symbol.iterator]();
for (const value of iterator) {
console.log(value);
if (value === 1) {
break;
}
console.log("This string will not be logged.");
}
// 1
// Another loop using the same iterator
// picks up where the last loop left off.
for (const value of iterator) {
console.log(value);
}
// 2
// 3
// The iterator is used up.
// This loop will execute no iterations.
for (const value of iterator) {
console.log(value);
}
// [No output]
生成器实现了 return()
方法,这使得生成器函数在循环退出时提前返回。这使得生成器无法在循环之间重用。
¥Generators implement the return()
method, which causes the generator function to early return when the loop exits. This makes generators not reusable between loops.
function* source() {
yield 1;
yield 2;
yield 3;
}
const generator = source();
for (const value of generator) {
console.log(value);
if (value === 1) {
break;
}
console.log("This string will not be logged.");
}
// 1
// The generator is used up.
// This loop will execute no iterations.
for (const value of generator) {
console.log(value);
}
// [No output]
for...of 和 for...in 之间的区别
¥Difference between for...of and for...in
for...in
和 for...of
语句都会迭代某些内容。它们之间的主要区别在于它们迭代的内容。
¥Both for...in
and for...of
statements iterate over something. The main difference between them is in what they iterate over.
for...in
语句迭代对象的 可枚举字符串属性,而 for...of
语句迭代 可迭代对象 定义要迭代的值。
¥The for...in
statement iterates over the enumerable string properties of an object, while the for...of
statement iterates over values that the iterable object defines to be iterated over.
以下示例显示了 for...of
循环和 for...in
循环与 Array
一起使用时的区别。
¥The following example shows the difference between a for...of
loop and a for...in
loop when used with an Array
.
Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};
const iterable = [3, 5, 7];
iterable.foo = "hello";
for (const i in iterable) {
console.log(i);
}
// "0", "1", "2", "foo", "arrCustom", "objCustom"
for (const i in iterable) {
if (Object.hasOwn(iterable, i)) {
console.log(i);
}
}
// "0" "1" "2" "foo"
for (const i of iterable) {
console.log(i);
}
// 3 5 7
对象 iterable
继承属性 objCustom
和 arrCustom
,因为它的 原型链 中同时包含 Object.prototype
和 Array.prototype
。
¥The object iterable
inherits the properties objCustom
and arrCustom
because it contains both Object.prototype
and Array.prototype
in its prototype chain.
for...in
循环仅记录 iterable
对象的 可枚举属性。它不会记录数组元素 3
、5
、7
或 "hello"
,因为这些不是属性 - 它们是值。它记录数组索引以及 arrCustom
和 objCustom
,它们是实际属性。如果你不确定为什么要迭代这些属性,这里有关于 数组迭代和 for...in
如何工作的更全面的解释。
¥The for...in
loop logs only enumerable properties of the iterable
object. It doesn't log array elements 3
, 5
, 7
or "hello"
because those are not properties — they are values. It logs array indexes as well as arrCustom
and objCustom
, which are actual properties. If you're not sure why these properties are iterated over, there's a more thorough explanation of how array iteration and for...in
work.
第二个循环与第一个循环类似,但它使用 Object.hasOwn()
来检查找到的可枚举属性是否是对象自己的,即不是继承的。如果是,则记录该属性。属性 0
、1
、2
和 foo
会被记录,因为它们是自己的属性。属性 arrCustom
和 objCustom
不会被记录,因为它们是继承的。
¥The second loop is similar to the first one, but it uses Object.hasOwn()
to check if the found enumerable property is the object's own, i.e. not inherited. If it is, the property is logged. Properties 0
, 1
, 2
and foo
are logged because they are own properties. Properties arrCustom
and objCustom
are not logged because they are inherited.
for...of
循环迭代并记录 iterable
作为数组(即 iterable)定义要迭代的值。显示了对象的元素 3
、5
、7
,但没有显示对象的任何属性。
¥The for...of
loop iterates and logs values that iterable
, as an array (which is iterable), defines to be iterated over. The object's elements 3
, 5
, 7
are shown, but none of the object's properties are.
规范
Specification |
---|
ECMAScript Language Specification # sec-for-in-and-for-of-statements |
浏览器兼容性
BCD tables only load in the browser