要让类实例支持for...of等遍历,需定义[Symbol.iterator]方法返回符合迭代器协议的对象;若需异步遍历,则实现[Symbol.asyncIterator]方法。
要让一个类实例能被 for...of、扩展运算符([...obj])、解构等语法遍历,关键是在该实例上定义 [symbol.iterator] 方法,返回一个符合迭代器协议的对象(即有 next() 方法,返回 { value, done } 形式的对象)。
1. 基础实现:返回简单值序列
最常见场景是让实例按某种顺序“产出”内部数据(如数组、Map 的键/值等)。只需在类的原型或实例上定义 [Symbol.iterator],返回一个闭包内的迭代器函数即可:
示例:遍历类内部维护的 items 数组
[Symbol.iterator]
- 不直接在
[Symbol.iterator]中硬编码逻辑,而是委托给一个私有方法(如_getIterator(mode)) - 让
[Symbol.iterator]默认返回一种模式(如 values),其他模式通过显式方法调用(.keys()、.entries())获取 - 确保所有返回的迭代器都满足协议:每次调用
next()返回{ value, done }
示例:模拟 Map 的遍历接口
class MyMap {
constructor(entries = []) {
this._data = new Map(entries);
}
[Symbol.iterator]() {
return this.values(); // 默认遍历值
}
*keys() {
for (const key of this._data.keys()) {
yield key;
}
}
*values() {
for (const value of this._data.values()) {
yield value;
}
}
*entries() {
for (const entry of this._data.entries()) {
yield entry;
}
}
}
注意:这里用了生成器函数(function* 或 *method()),它天然返回迭代器,写法更简洁、状态自动管理,推荐优先使用。
3. 注意事项与常见陷阱
-
必须返回迭代器对象:不是直接返回值,也不是返回普通对象;必须有
next()方法,且每次调用返回{ value, done } -
done 为 true 后仍可调用 next():规范要求后续调用应始终返回
{ value: undefined, done: true },需在逻辑中处理越界情况 -
避免闭包引用外部可变状态出错:若迭代器依赖实例属性(如
this.items),而该属性在遍历中途被修改,行为可能不符合预期;必要时可提前快照(如const items = [...this.items]) -
生成器函数是首选:比手写
next()更安全、易读、支持yield*、异步迭代(async function*)等高级特性
4. 进阶:支持异步迭代(AsyncIterator)
若数据源是异步的(如从 API 分页加载),可实现 [Symbol.asyncIterator],返回一个异步迭代器(next() 返回 Promise):
class AsyncCollection {
constructor(fetcher) {
this.fetcher = fetcher; // (page) => Promise<items>
}
async *[Symbol.asyncIterator]() {
let page = 1;
while (true) {
const items = await this.fetcher(page);
if (items.length === 0) break;
for (const item of items) {
yield item;
}
page++;
}
}
}
// 使用:
// for await (const item of asyncColl) { ... }
</items>










