迭代器

Iterator 对象是通过提供返回迭代器结果对象的 next() 方法来符合 迭代器协议 的对象。所有内置迭代器都继承自 Iterator 类。Iterator 类提供了一个 @@iterator 方法,该方法返回迭代器对象本身,使迭代器也成为 iterable。它还提供了一些使用迭代器的辅助方法。

¥An Iterator object is an object that conforms to the iterator protocol by providing a next() method that returns an iterator result object. All built-in iterators inherit from the Iterator class. The Iterator class provides a @@iterator method that returns the iterator object itself, making the iterator also iterable. It also provides some helper methods for working with iterators.

描述

¥Description

以下都是内置的 JavaScript 迭代器:

¥The following are all built-in JavaScript iterators:

每个迭代器都有一个不同的原型对象,它定义特定迭代器使用的 next() 方法。例如,所有字符串迭代器对象都继承自隐藏对象 StringIteratorPrototype,该对象具有按代码点迭代此字符串的 next() 方法。StringIteratorPrototype 还有一个 @@toStringTag 属性,其初始值为字符串 "String Iterator"。该属性在 Object.prototype.toString() 中使用。同样,其他迭代器原型也有自己的 @@toStringTag 值,与上面给出的名称相同。

¥Each of these iterators have a distinct prototype object, which defines the next() method used by the particular iterator. For example, all string iterator objects inherit from a hidden object StringIteratorPrototype, which has a next() method that iterates this string by code points. StringIteratorPrototype also has a @@toStringTag property whose initial value is the string "String Iterator". This property is used in Object.prototype.toString(). Similarly, other iterator prototypes also have their own @@toStringTag values, which are the same as the names given above.

所有这些原型对象都继承自 Iterator.prototypeIterator.prototype 提供了返回迭代器对象本身的 @@iterator 方法,使得迭代器也是 iterable

¥All of these prototype objects inherit from Iterator.prototype, which provides a @@iterator method that returns the iterator object itself, making the iterator also iterable.

迭代器助手

¥Iterator helpers

注意:这些方法是迭代器助手,而不是可迭代助手,因为对象可迭代的唯一要求就是存在 @@iterator 方法。没有可安装这些方法的共享原型。

¥Note: These methods are iterator helpers, not iterable helpers, because the only requirement for an object to be iterable is just the presence of a @@iterator method. There is no shared prototype to install these methods on.

Iterator 类本身提供了一些用于使用迭代器的辅助方法。例如,你可能想做以下事情:

¥The Iterator class itself provides some helper methods for working with iterators. For example, you may be tempted to do the following:

js
const nameToDeposit = new Map([
  ["Anne", 1000],
  ["Bert", 1500],
  ["Carl", 2000],
]);

const totalDeposit = [...nameToDeposit.values()].reduce((a, b) => a + b);

首先将 Map.prototype.values() 返回的迭代器转换为数组,然后使用 Array.prototype.reduce() 方法计算总和。但是,这会创建一个中间数组并迭代该数组两次。相反,你可以使用迭代器本身的 reduce() 方法:

¥This first converts the iterator returned by Map.prototype.values() to an array, then uses the Array.prototype.reduce() method to calculate the sum. However, this both creates an intermediate array and iterates the array twice. Instead, you can use the reduce() method of the iterator itself:

js
const totalDeposit = nameToDeposit.values().reduce((a, b) => a + b);

这种方法更加高效,因为它只迭代迭代器一次,而不需要记住任何中间值。迭代器辅助方法对于使用无限迭代器是必需的:

¥This method is more efficient, because it only iterates the iterator once, without memorizing any intermediate values. Iterator helper methods are necessary to work with infinite iterators:

js
function* fibonacci() {
  let current = 1;
  let next = 1;
  while (true) {
    yield current;
    [current, next] = [next, current + next];
  }
}

const seq = fibonacci();
const firstThreeDigitTerm = seq.find((n) => n >= 100);

你无法将 seq 转换为数组,因为它是无限的。相反,你可以使用迭代器本身的 find() 方法,该方法仅根据需要迭代 seq 以找到满足条件的第一个值。

¥You cannot convert seq to an array, because it is infinite. Instead, you can use the find() method of the iterator itself, which only iterates seq as far as necessary to find the first value that satisfies the condition.

你会发现许多迭代器方法类似于数组方法,例如:

¥You will find many iterator methods analogous to array methods, such as:

迭代器方法 数组法
Iterator.prototype.every() Array.prototype.every()
Iterator.prototype.filter() Array.prototype.filter()
Iterator.prototype.find() Array.prototype.find()
Iterator.prototype.flatMap() Array.prototype.flatMap()
Iterator.prototype.forEach() Array.prototype.forEach()
Iterator.prototype.map() Array.prototype.map()
Iterator.prototype.reduce() Array.prototype.reduce()
Iterator.prototype.some() Array.prototype.some()

Iterator.prototype.drop()Iterator.prototype.take() 组合起来有点类似于 Array.prototype.slice()

¥Iterator.prototype.drop() and Iterator.prototype.take() combined are somewhat analogous to Array.prototype.slice().

其中,filter()flatMap()map()drop()take() 返回一个新的 Iterator Helper 对象。迭代器助手也是一个 Iterator 实例,使得助手方法可链接。所有迭代器辅助对象都继承自一个公共原型对象,该对象实现了迭代器协议:

¥Among these methods, filter(), flatMap(), map(), drop(), and take() return a new Iterator Helper object. The iterator helper is also an Iterator instance, making the helper methods chainable. All iterator helper objects inherit from a common prototype object, which implements the iterator protocol:

next()

调用底层迭代器的 next() 方法,将辅助方法应用于结果,并返回结果。

return()

调用底层迭代器的 return() 方法,并返回结果。

迭代器助手与底层迭代器共享相同的数据源,因此迭代迭代器助手会导致底层迭代器也被迭代。没有办法对迭代器进行 "fork" 来允许它被迭代多次。

¥The iterator helper shares the same data source as the underlying iterator, so iterating the iterator helper causes the underlying iterator to be iterated as well. There is no way to "fork" an iterator to allow it to be iterated multiple times.

js
const it = [1, 2, 3].values();
const it2 = it.drop(0); // Essentially a copy
console.log(it.next().value); // 1
console.log(it2.next().value); // 2
console.log(it.next().value); // 3

适当的迭代器

¥Proper iterators

"iterators" 有两种:符合 迭代器协议 的对象(至少只需要存在 next() 方法),以及从 Iterator 类继承的对象,它们使用辅助方法。它们并不相互蕴涵 - 从 Iterator 继承的对象不会自动成为迭代器,因为 Iterator 类没有定义 next() 方法。相反,该对象需要自己定义一个 next() 方法。正确的迭代器是既符合迭代器协议又继承自 Iterator 的迭代器,并且大多数代码期望迭代器是正确的迭代器并且可迭代器返回正确的迭代器。要创建正确的迭代器,请定义一个扩展 Iterator 的类,或使用 Iterator.from() 方法。

¥There are two kinds of "iterators": objects that conform to the iterator protocol (which, at its minimum, only requires the presence of a next() method), and objects that inherit from the Iterator class, which enjoy the helper methods. They do not entail each other — objects that inherit from Iterator do not automatically become iterators, because the Iterator class does not define a next() method. Instead, the object needs to define a next() method itself. A proper iterator is one that both conforms to the iterator protocol and inherits from Iterator, and most code expect iterators to be proper iterators and iterables to return proper iterators. To create proper iterators, define a class that extends Iterator, or use the Iterator.from() method.

js
class MyIterator extends Iterator {
  next() {
    // …
  }
}

const myIterator = Iterator.from({
  next() {
    // …
  },
});

构造函数

¥Constructor

Iterator() Experimental

旨在由创建迭代器的其他类实现 extended。自己构造时会抛出错误。

静态方法

¥Static methods

Iterator.from() Experimental

从迭代器或可迭代对象创建新的 Iterator 对象。

实例属性

¥Instance properties

这些属性在 Iterator.prototype 上定义并由所有 Iterator 实例共享。

¥These properties are defined on Iterator.prototype and shared by all Iterator instances.

Iterator.prototype.constructor

创建实例对象的构造函数。对于 Iterator 实例,初始值为 Iterator 构造函数。

Iterator.prototype[@@toStringTag]

@@toStringTag 属性的初始值为字符串 "Iterator"。该属性在 Object.prototype.toString() 中使用。

注意:与大多数内置类上的 @@toStringTag 不同,出于 Web 兼容性原因,Iterator.prototype[@@toStringTag] 是可写的。

¥Note: Unlike the @@toStringTag on most built-in classes, Iterator.prototype[@@toStringTag] is writable for web compatibility reasons.

实例方法

¥Instance methods

Iterator.prototype.drop() Experimental

返回一个新的迭代器助手,该助手会在此迭代器开头跳过给定数量的元素。

Iterator.prototype.every() Experimental

测试迭代器生成的所有元素是否通过所提供函数实现的测试。

Iterator.prototype.filter() Experimental

返回一个新的迭代器辅助程序,它仅生成提供的回调函数返回 true 的迭代器元素。

Iterator.prototype.find() Experimental

返回迭代器产生的第一个满足所提供的测试函数的元素。如果没有值满足测试函数,则返回 undefined

Iterator.prototype.flatMap() Experimental

返回一个新的迭代器辅助程序,它获取原始迭代器中的每个元素,通过映射函数运行它,并生成映射函数返回的元素(包含在另一个迭代器或可迭代器中)。

Iterator.prototype.forEach() Experimental

对迭代器生成的每个元素执行一次提供的函数。

Iterator.prototype.map() Experimental

返回一个新的迭代器助手,它生成迭代器的元素,每个元素都由映射函数转换。

Iterator.prototype.reduce() Experimental

对迭代器生成的每个元素执行用户提供的 "reducer" 回调函数,并传入前一个元素计算的返回值。在所有元素上运行减速器的最终结果是一个值。

Iterator.prototype.some() Experimental

测试迭代器中的至少一个元素是否通过所提供函数实现的测试。它返回一个布尔值。

Iterator.prototype.take() Experimental

返回一个新的迭代器助手,该迭代器助手在此迭代器中生成给定数量的元素,然后终止。

Iterator.prototype.toArray() Experimental

创建一个新的 Array 实例,其中填充了迭代器生成的元素。

Iterator.prototype[@@iterator]()

返回迭代器对象本身。这允许迭代器对象也是可迭代的。

示例

¥Examples

将迭代器用作可迭代对象

¥Using an iterator as an iterable

所有内置迭代器也是可迭代的,因此你可以在 for...of 循环中使用它们:

¥All built-in iterators are also iterable, so you can use them in a for...of loop:

js
const arrIterator = [1, 2, 3].values();
for (const value of arrIterator) {
  console.log(value);
}
// Logs: 1, 2, 3

规范

Specification
ECMAScript Language Specification
# sec-%iteratorprototype%-object

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看