根本原因是迭代器为一次性消费对象,内部状态不可逆且无重置机制;每次for...of需调用[Symbol.iterator]()获取新实例,已耗尽的迭代器反复调用next()始终返回{value: undefined, done: true}。

同一个迭代器对象不能重复用于多个 for...of 循环,根本原因在于:迭代器是“一次性消费”的——它内部维护一个不可逆的遍历状态(比如当前索引、已读标记或生成器暂停位置),一旦遍历结束(done: true),后续调用 next() 永远返回 { value: undefined, done: true },无法重置。
迭代器对象本身不保存“可重用”能力
迭代器协议只要求实现 next() 方法,并不要求支持 reset()、rewind() 或 clone()。也就是说:
- 每次调用
[Symbol.iterator]()才会创建一个**新**的迭代器实例; - 已存在的迭代器对象(比如从
arr[Symbol.iterator]()拿到的那个)只负责单次线性遍历; - 反复对它执行
for...of,等价于反复调用它的next()—— 第二次开始就直接从上次停下的位置继续,通常很快就会返回done: true,什么也不输出。
实际例子看状态不可逆
以数组为例:
const arr = [10, 20, 30];
const it = arr[Symbol.iterator](); // 创建一次迭代器
console.log(it.next()); // { value: 10, done: false }
console.log(it.next()); // { value: 20, done: false }
console.log(it.next()); // { value: 30, done: false }
console.log(it.next()); // { value: undefined, done: true }
console.log(it.next()); // { value: undefined, done: true } ← 后续全一样
此时再写 for (const x of it) { ... },循环体一次都不会执行,因为第一次 it.next() 就返回 done: true。
为什么 for...of 不自动重置?
for...of 的设计逻辑是“消费迭代器”,不是“控制迭代器”。它只做三件事:
- 调用对象的
[Symbol.iterator]()获取迭代器(注意:这是**获取**,不是复用已有对象); - 反复调用该迭代器的
next()直到done: true; - 不关心、也不提供重置机制——这由迭代器的实现者决定(而标准迭代器不实现重置)。
所以,如果你写 for (x of it) 两次,第二次传入的是同一个已耗尽的 it,不是重新调用 [Symbol.iterator]。
如何真正“重复遍历”?
关键不是让迭代器重用,而是每次需要时都新建一个:
- ✅ 正确:直接对原对象用
for...of(如for (x of arr))——每次都会触发arr[Symbol.iterator](),拿到新迭代器; - ✅ 正确:手动再调一次
arr[Symbol.iterator]()得到新实例; - ❌ 错误:把
it = arr[Symbol.iterator]()存起来,然后反复for (x of it)。
自定义迭代器若想支持重复使用,必须在 next() 中自行管理状态并允许重放(比如每次调用都重置内部索引),但这违背常规语义,一般不推荐。

















