Iterator
Baseline 广泛可用 *
一个 Iterator 对象是一个符合迭代器协议的对象,它通过提供一个 next() 方法来返回一个迭代器结果对象。所有内置迭代器都继承自 Iterator 类。Iterator 类提供了一个 [Symbol.iterator]() 方法,该方法返回迭代器对象本身,使得迭代器也成为可迭代对象。它还提供了一些用于处理迭代器的辅助方法。
描述
以下是所有内置的 JavaScript 迭代器:
- 由
Array.prototype.values()、Array.prototype.keys()、Array.prototype.entries()、Array.prototype[Symbol.iterator]()、TypedArray.prototype.values()、TypedArray.prototype.keys()、TypedArray.prototype.entries()、TypedArray.prototype[Symbol.iterator]()和arguments[Symbol.iterator]()返回的 数组迭代器。 - 由
String.prototype[Symbol.iterator]()返回的 字符串迭代器。 - 由
Map.prototype.values()、Map.prototype.keys()、Map.prototype.entries()和Map.prototype[Symbol.iterator]()返回的 Map 迭代器。 - 由
Set.prototype.values()、Set.prototype.keys()、Set.prototype.entries()和Set.prototype[Symbol.iterator]()返回的 Set 迭代器。 - 由
RegExp.prototype[Symbol.matchAll]()和String.prototype.matchAll()返回的 RegExp 字符串迭代器。 - 由生成器函数返回的
Generator对象。 - 由
Intl.Segmenter.prototype.segment()返回的Segments对象的[Symbol.iterator]()方法返回的 分段迭代器。 - 由迭代器辅助方法(如
Iterator.prototype.filter()和Iterator.prototype.map())返回的 迭代器辅助器。
Web API 也可能返回迭代器。有些重用了核心 JavaScript 迭代器,而另一些则定义了自己的迭代器。例如:
- 类数组对象,例如
NodeList,从其各自的keys()、values()、entries()和[Symbol.iterator]()方法返回一个 数组迭代器。 - 来自 Web API 的类 Map 对象,例如
Headers,从其各自的keys()、values()、entries()和[Symbol.iterator]()方法返回其自己的迭代器类型,如 Headers 迭代器。 - 来自 Web API 的类 Set 对象,例如
FontFaceSet,从其各自的keys()、values()、entries()和[Symbol.iterator]()方法返回其自己的迭代器类型,如 FontFaceSet 迭代器。
注意: NodeIterator 和其他旧接口虽然名称如此,但并不符合迭代器协议或可迭代协议。
这些迭代器中的每一个都有一个独特的原型对象,它定义了特定迭代器使用的 next() 方法。例如,所有字符串迭代器对象都继承自一个隐藏对象 StringIteratorPrototype,它有一个 next() 方法,该方法按代码点迭代字符串。StringIteratorPrototype 还有一个 [Symbol.toStringTag] 属性,其初始值为字符串 "String Iterator"。此属性在 Object.prototype.toString() 中使用。类似地,其他迭代器原型也有自己的 [Symbol.toStringTag] 值,这些值与上面给出的名称相同。
所有这些原型对象都继承自 Iterator.prototype,它提供了一个 [Symbol.iterator]() 方法,该方法返回迭代器对象本身,使迭代器也成为可迭代对象。
迭代器辅助方法
注意: 这些方法是迭代器辅助方法,而不是可迭代对象辅助方法,因为对象可迭代的唯一要求是存在 [Symbol.iterator]() 方法。没有共享的原型来安装这些方法。
Iterator 类本身提供了一些用于处理迭代器的辅助方法。例如,您可能会尝试以下操作:
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() 方法:
const totalDeposit = nameToDeposit.values().reduce((a, b) => a + b);
这种方法可能更有效,尤其是在内存方面,因为它只迭代迭代器一次,而不记忆任何中间值。迭代器辅助方法对于处理无限迭代器是必要的。
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 以找到满足条件的第一个值。
您会发现许多迭代器方法与数组方法类似,例如:
Iterator.prototype.drop() 和 Iterator.prototype.take() 结合起来有点类似于 Array.prototype.slice()。
迭代器辅助对象
注意: 迭代器辅助对象和迭代器辅助方法是两个不同的概念。迭代器辅助对象可以在运行时检测到,而“迭代器辅助方法”只是用于理解的一组方法的名称。迭代器辅助器可能指对象或方法,具体取决于上下文。
在迭代器辅助方法中,filter()、flatMap()、map()、drop() 和 take() 返回一个新的 迭代器辅助器 对象。迭代器辅助器也是一个 Iterator 实例,这使得这些辅助方法可以链式调用。所有迭代器辅助对象都继承自一个公共原型对象,该对象实现了迭代器协议:
迭代器辅助器与底层迭代器共享相同的数据源,因此迭代迭代器辅助器也会导致底层迭代器被迭代。没有办法“分叉”一个迭代器以使其能够多次迭代。
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
真正的迭代器
有两种“迭代器”:符合迭代器协议的对象(最少只要求存在 next() 方法),以及继承自 Iterator 类并享有辅助方法的对象。它们并不相互包含——继承自 Iterator 的对象不会自动成为迭代器,因为 Iterator 类不定义 next() 方法。相反,对象需要自己定义一个 next() 方法。一个真正的迭代器是既符合迭代器协议又继承自 Iterator 的迭代器,并且大多数代码期望迭代器是真正的迭代器,并且可迭代对象返回真正的迭代器。要创建真正的迭代器,可以定义一个扩展 Iterator 的类,或使用 Iterator.from() 方法。
class MyIterator extends Iterator {
next() {
// …
}
}
const myIterator = Iterator.from({
next() {
// …
},
});
构造函数
Iterator()-
旨在被创建迭代器的其他类扩展。如果单独构造,会抛出错误。
静态方法
Iterator.from()-
从迭代器或可迭代对象创建一个新的
Iterator对象。
实例属性
这些属性在 Iterator.prototype 上定义,并由所有 Iterator 实例共享。
Iterator.prototype.constructor-
创建实例对象的构造函数。对于
Iterator实例,初始值是Iterator构造函数。 Iterator.prototype[Symbol.toStringTag]-
[Symbol.toStringTag]属性的初始值为字符串"Iterator"。此属性在Object.prototype.toString()中使用。注意: 与大多数内置类上的
[Symbol.toStringTag]不同,Iterator.prototype[Symbol.toStringTag]是可写的,这是出于 Web 兼容性原因。
实例方法
Iterator.prototype.drop()-
返回一个新的迭代器辅助对象,该对象跳过此迭代器开头的给定数量的元素。
Iterator.prototype.every()-
测试迭代器产生的所有元素是否通过提供的函数实现的测试。
Iterator.prototype.filter()-
返回一个新的迭代器辅助对象,该对象只生成迭代器中那些提供的回调函数返回
true的元素。 Iterator.prototype.find()-
返回迭代器产生的第一个满足提供的测试函数的元素。如果没有值满足测试函数,则返回
undefined。 Iterator.prototype.flatMap()-
返回一个新的迭代器辅助对象,该对象接受原始迭代器中的每个元素,通过映射函数处理它,并生成映射函数返回的元素(这些元素包含在另一个迭代器或可迭代对象中)。
Iterator.prototype.forEach()-
对迭代器产生的每个元素执行一次提供的函数。
Iterator.prototype.map()-
返回一个新的迭代器辅助对象,该对象生成迭代器的元素,每个元素都由映射函数转换。
Iterator.prototype.reduce()-
对迭代器产生的每个元素执行一个用户提供的“reducer”回调函数,传入对前一个元素计算的返回值。运行 reducer 对所有元素的最终结果是一个单一值。
Iterator.prototype.some()-
测试迭代器中至少有一个元素通过提供的函数实现的测试。它返回一个布尔值。
Iterator.prototype.take()-
返回一个新的迭代器辅助对象,该对象生成此迭代器中给定数量的元素,然后终止。
Iterator.prototype.toArray()-
创建一个新的
Array实例,其中填充了从迭代器生成的元素。 Iterator.prototype[Symbol.dispose]()-
如果存在,则调用
this的return()方法。这实现了可处置协议,并允许在使用using或await using时对其进行处置。 Iterator.prototype[Symbol.iterator]()-
返回迭代器对象本身。这使得迭代器对象也可以是可迭代的。
示例
将迭代器用作可迭代对象
所有内置迭代器也都是可迭代的,因此您可以在 for...of 循环中使用它们:
const arrIterator = [1, 2, 3].values();
for (const value of arrIterator) {
console.log(value);
}
// Logs: 1, 2, 3
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # sec-%iteratorprototype%-object |
浏览器兼容性
加载中…