Iterator
Iterator 是通过 next() 按次产出值的对象,是可迭代对象的执行结果。
#type / concept
#status / growing
#resource / javascript
#resource / ecmascript
[!info] related notes
- 所属 MOC: ES6 新特性 MOC, ECMAScript MOC
- 前置概念: Iterable
- 并列概念: Generator
- 关系笔记: Iterable、Iterator、Generator 关系
Iterator
一句话定义
Iterator 是一个带 next() 方法的对象,每次调用 next() 返回 { value, done },是逐步产出值的协议。
核心机制 / Symbol.iterator 协议
- 可迭代对象(Array、Map、Set、String 等)实现
Symbol.iterator方法。 - 调用
obj[Symbol.iterator]()返回一个迭代器对象。 - 迭代器对象有
next()方法,返回{ value, done }。 done: true之后的调用继续返回{ value: undefined, done: true }。
const arr = ['a', 'b', 'c'];
const iter = arr[Symbol.iterator]();
iter.next(); // { value: 'a', done: false }
iter.next(); // { value: 'b', done: false }
iter.next(); // { value: 'c', done: false }
iter.next(); // { value: undefined, done: true }
for…of 消费
// for...of 内部自动调用 Symbol.iterator
for (const item of ['x', 'y', 'z']) {
console.log(item); // x, y, z
}
// Map 迭代
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
console.log(key, value);
}
// String 迭代
for (const char of 'hello') {
console.log(char); // h, e, l, l, o
}
自定义迭代器
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
if (current <= end) {
return { value: current++, done: false };
}
return { value: undefined, done: true };
}
};
}
}
for (const n of new Range(1, 5)) {
console.log(n); // 1, 2, 3, 4, 5
}
// 展开运算符也消费迭代器
const nums = [...new Range(1, 3)]; // [1, 2, 3]
Generator 作为迭代器
function* range(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
// Generator 自带 Symbol.iterator,既可迭代又可单独当迭代器
const gen = range(1, 3);
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: 3, done: false }
gen.next(); // { value: undefined, done: true }
// 也可以直接 for...of
for (const n of range(1, 5)) {
console.log(n);
}
实际使用场景
// 无限序列
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
fib.next().value; // 0
fib.next().value; // 1
fib.next().value; // 1
fib.next().value; // 2
// 惰性处理大数据集
function* filter(iterable, predicate) {
for (const item of iterable) {
if (predicate(item)) yield item;
}
}
与 forEach 的区别
| 维度 | Iterator / for…of | forEach |
|---|---|---|
| 中途退出 | break / return 可以 | 不行(只能用 try/catch 绕过) |
| 惰性求值 | 支持(Generator) | 不支持,立即遍历全部 |
| 适用对象 | 所有可迭代对象 | 只有 Array、Map、Set |
| 异步 | for await...of | 不支持 |
边界与常见误解
- Iterator 通常是一次性的:遍历完就结束,不能重置。需要重新调用
Symbol.iterator获取新迭代器。 - Object 不是可迭代对象:普通
{}没有Symbol.iterator,不能直接for...of。需要Object.keys/values/entries。 - Iterator 不等于 Iterable:如果一个对象只有
next()但没有[Symbol.iterator](),它不能被for...of消费。实现[Symbol.iterator]() { return this; }可以让它同时是两者。 - 展开运算符
...、解构赋值、Array.from都消费迭代器。