JavaScript迭代器模式是一种行为设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。这种模式让不同的数据结构可以拥有统一的遍历接口,开发者不需要针对数组、对象、集合等不同结构编写不同的遍历逻辑。Generator函数是ES6引入的特殊函数,执行后返回的对象天然符合迭代器协议,大幅降低了迭代器的实现成本。

迭代器模式的核心概念
迭代器模式主要包含两个核心协议:可迭代协议和迭代器协议。
可迭代协议
如果一个对象实现了Symbol.iterator方法,那么这个对象就是可迭代的。该方法需要返回一个符合迭代器协议的对象。
迭代器协议
迭代器对象需要包含一个next方法,每次调用next方法会返回一个包含value和done两个属性的对象:value表示当前遍历到的值,done是布尔值,表示遍历是否已经结束。
手动实现迭代器模式
我们可以手动为一个自定义数据结构实现迭代器,以下是一个简单的范围迭代器实现:
// 自定义范围类,实现迭代器模式
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 };
} else {
return { value: undefined, done: true };
}
}
};
}
}
// 使用自定义迭代器
const range = new Range(1, 3);
for (const num of range) {
console.log(num); // 依次输出1、2、3
}
Generator函数的基本用法
Generator函数是ES6提供的用来异步编程的解决方案,它的语法行为与传统函数完全不同。Generator函数有两个特征:一是function关键字与函数名之间有一个星号;二是函数体内部使用yield表达式定义不同的内部状态。
执行Generator函数会返回一个遍历器对象,该对象也符合迭代器协议,因此可以直接用于for...of循环等需要迭代器的场景。
// 基本Generator函数示例
function* simpleGenerator() {
yield '第一个状态';
yield '第二个状态';
return '结束状态';
}
const gen = simpleGenerator();
console.log(gen.next()); // { value: '第一个状态', done: false }
console.log(gen.next()); // { value: '第二个状态', done: false }
console.log(gen.next()); // { value: '结束状态', done: true }
console.log(gen.next()); // { value: undefined, done: true }
用Generator函数实现迭代器功能
Generator函数天然支持迭代器协议,用它实现迭代器比手动编写要简洁很多。我们可以用Generator函数重写前面的范围迭代器:
// 用Generator函数实现范围迭代器
class GeneratorRange {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
let current = this.start;
while (current <= this.end) {
yield current;
current++;
}
}
}
// 使用Generator实现的迭代器
const genRange = new GeneratorRange(1, 3);
for (const num of genRange) {
console.log(num); // 依次输出1、2、3
}
可以看到,使用Generator函数实现迭代器时,不需要手动维护next方法和状态对象,只需要在函数内部通过yield依次返回需要遍历的值即可,Generator函数会自动处理迭代的状态管理。
两种实现方式的对比
| 对比维度 | 手动实现迭代器 | Generator函数实现 |
|---|---|---|
| 代码复杂度 | 需要手动编写next方法,维护遍历状态 | 只需用yield返回遍历值,状态自动管理 |
| 可读性 | 逻辑分散,需要理解迭代器协议细节 | 逻辑线性,更符合同步代码的阅读习惯 |
| 适用场景 | 需要完全自定义迭代逻辑时使用 | 大多数常规迭代场景,尤其是复杂遍历逻辑 |
Generator迭代器的常见应用场景
- 处理大型数据集的惰性遍历,避免一次性加载所有数据占用过多内存
- 实现异步操作的同步化表达,结合
yield处理异步流程 - 自定义复杂数据结构的遍历逻辑,比如树形结构的深度优先遍历
以下是一个树形结构遍历的示例,用Generator函数实现深度优先遍历:
// 树节点结构
const tree = {
value: '根节点',
children: [
{
value: '子节点1',
children: [
{ value: '子节点1-1', children: [] },
{ value: '子节点1-2', children: [] }
]
},
{
value: '子节点2',
children: [
{ value: '子节点2-1', children: [] }
]
}
]
};
// 深度优先遍历的Generator实现
function* depthFirstTraverse(node) {
yield node.value;
for (const child of node.children) {
yield* depthFirstTraverse(child);
}
}
// 遍历树结构
for (const value of depthFirstTraverse(tree)) {
console.log(value); // 依次输出:根节点、子节点1、子节点1-1、子节点1-2、子节点2、子节点2-1
}
通过Generator函数实现迭代器模式,不仅减少了代码量,还让遍历逻辑更加清晰,开发者可以更专注于业务本身的实现,而不需要花费过多精力处理迭代器的底层协议细节。
JavaScript迭代器模式Generator函数Iterator迭代协议修改时间:2026-06-30 14:18:31