JavaScript中自定义遍历流程的核心是实现迭代器协议:对象需有[Symbol.iterator]方法,该方法返回含next()的对象,next()返回{value, done}结构。

JavaScript 中自定义遍历流程的核心是实现迭代器协议(Iterator Protocol)——让对象拥有可被 for...of、展开运算符([...obj])、解构等语法消费的能力。关键不是写个循环,而是返回一个符合规范的迭代器对象。
迭代器协议的两个必要条件
一个对象要支持自定义遍历,必须满足:
- 拥有一个名为
[Symbol.iterator]的方法(即 可迭代协议); - 该方法返回的对象必须实现 迭代器协议:有
next()方法,且每次调用返回形如{ value: any, done: boolean }的对象。
手写一个简单可迭代对象
比如想让一个自定义的范围类 Range 支持 for...of 遍历:
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
return {
next() {
if (current < this.end) {
return { value: current++, done: false };
}
return { value: undefined, done: true };
}
};
}
}
注意:next 方法里的 this 指向的是返回的迭代器对象(不是 Range 实例),所以上面代码会出错。正确写法需绑定上下文或用闭包:
立即学习“Java免费学习笔记(深入)”;
[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, 4)) {
console.log(n); // 1, 2, 3
}
用生成器函数简化实现
手动写 next() 容易出错且逻辑分散。更推荐用 function* 生成器函数——它天然返回符合迭代器协议的对象:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i < this.end; i++) {
yield i;
}
}
}
生成器内部自动维护状态,yield 对应 value,函数结束自动返回 done: true,语义清晰、不易出错。
支持提前终止(可选但实用)
如果遍历可能被 break、return 或异常中断,可以给迭代器添加 return() 方法,用于清理资源(如关闭连接、释放内存):
*[Symbol.iterator]() {
let current = this.start;
try {
while (current < this.end) {
yield current++;
}
} finally {
// 可在此做清理,比如 console.log('cleanup');
}
}
或者显式实现 return:
[Symbol.iterator]() {
let current = this.start;
const iterator = {
next() {
if (current < this.end) return { value: current++, done: false };
return { done: true };
},
return() {
console.log('迭代被提前终止');
return { value: undefined, done: true };
}
};
return iterator;
}
当 for...of 中遇到 break,引擎会自动调用 iterator.return()(如果存在)。
常见陷阱和注意事项
自定义迭代器时容易忽略的细节:
-
[Symbol.iterator]必须是**零参数函数**,不能带参数; - 每次调用
[Symbol.iterator]()应返回**新迭代器**,否则多次遍历会相互影响(比如数组的[Symbol.iterator]每次都返回独立迭代器); -
value在done: true时可省略,但若提供,应有意义(如最后的默认值); - 迭代器对象不必是“类实例”,普通对象 + 方法即可,但需确保
next()可重复调用且状态正确。
不复杂但容易忽略:协议本身很轻量,关键是理解 Symbol.iterator 是入口,next() 是契约。用好生成器,90% 的场景都能干净解决。

















