迭代器的next()方法返回{value: ..., done: true/false}对象,done为true后必须稳定返回{value: undefined, done: true},value类型任意,判断结束唯看done。

迭代器对象的 next() 方法到底返回什么
迭代器的核心是一个有 next() 方法的对象,每次调用都返回形如 { value: ..., done: true/false } 的对象。重点不是“它能循环”,而是“它把状态封装在自身内部”——done: true 之后再调用 next(),仍应返回 { value: undefined, done: true },这是规范要求,不是可选行为。
常见错误是手动实现迭代器时忽略 done 的终态处理,导致后续调用返回 { value: ..., done: false } 或抛错。例如自定义数组迭代器,没在越界后稳定返回 done: true,就会让 for...of 循环多跑一次或卡住。
-
value可以是任意类型,包括undefined;判断是否结束必须看done,不能靠value === undefined - 原生数组、Map、Set 的迭代器都满足“多次调用
next()不改变已返回项”,但自定义迭代器若依赖外部可变状态(比如共享的index变量),就可能不满足这一隐含契约 - ES2024 起部分引擎对
done: false后还继续返回值的迭代器更严格,会提前终止消费
生成器函数为什么能暂停执行
function* 声明的函数不立即运行,而是返回一个迭代器对象;每次调用它的 next(),才从上次 yield 暂停处恢复,并执行到下一个 yield 或 return。关键在于:函数体内的执行上下文(变量、作用域、指令指针)被引擎保存在生成器对象内部,不是靠闭包模拟。
容易误解的是把 yield 当作“返回并丢弃状态”。实际上:yield 表达式本身有返回值(由下一次 next(arg) 的 arg 决定),且函数暂停时所有局部变量依然存活。
立即学习“Java免费学习笔记(深入)”;
- 第一次
next()进入函数体,执行到第一个yield就暂停;该yield右侧表达式的结果成为本次value - 第二次
next('hello'),函数体内yield表达式的值就是'hello',可用于赋值:const x = yield 123→ 下次next('hello')后x === 'hello' - 生成器一旦执行到
return或自然结束,后续next()都返回{ value: ..., done: true },无法重置
for...of 和扩展运算符如何触发迭代协议
它们不关心对象是不是数组,只检查对象是否有 [Symbol.iterator] 方法。如果存在,就调用它获取迭代器,然后反复调用 next() 直到 done: true。这意味着:任何实现了迭代协议的对象,都能被 for...of、[...iterable]、Array.from() 等直接消费。
典型陷阱是误以为“可遍历 = 有 length 和数字键”。比如普通对象 { a: 1, b: 2 } 即使加了 length 属性,也不可被 for...of 遍历,除非手动部署 [Symbol.iterator]。
- 原生字符串、TypedArray、arguments 对象都内置了
[Symbol.iterator];普通对象没有,但可以自己加:obj[Symbol.iterator] = function*() { yield* Object.entries(this); } - 扩展运算符对迭代器是“一次性消费”,不会缓存结果;若迭代器有副作用(如读取流、生成随机数),重复展开会得到不同结果
-
yield*是委托语法,不是语法糖——它把控制权完整交给另一个可迭代对象,期间任何throw()或return()都会透传过去
生成器和异步代码混用时的常见断裂点
生成器本身是同步的,yield 不会让出事件循环。想用它写异步逻辑(如 yield fetch(...)),必须配合额外的执行器(如 co 库)或手动 Promise.then() 链。现代开发中,async/await 已取代这种模式,但理解断裂点仍有价值。
最常踩的坑是混淆“生成器暂停”和“异步等待”:在 yield Promise.resolve(42) 中,Promise 立即 resolve,生成器拿到的是已兑现的 Promise 对象,而非 42;要得到 42,得用 await 或手动 .then()。
- 生成器函数内不能直接
await,必须写成async function*(异步生成器),此时next()返回Promise,需await iterator.next() -
yield后接 Promise 不会自动 await,这和async/await的语义完全不同 - 调试时注意:生成器的堆栈跟踪通常不包含
yield暂停点,V8 的generator.next()调用看起来像普通函数调用
真正难的不是写出能跑的生成器,而是判断某个场景里是否该用它——比如需要早停的搜索、资源分片加载、状态机建模时,生成器天然合适;而只是想等个接口,async/await 更直白,也更容易被团队理解和维护。











