JavaScript迭代器是约定含next()方法并返回{value, done}对象的接口;数组等内置类型需先调用[Symbol.iterator]()获取迭代器;Generator函数返回可暂停恢复的迭代器,适用于无限序列、异步建模和状态机。

JavaScript 迭代器接口长什么样
迭代器不是语法糖,而是一个**约定好的对象接口**:只要一个对象有 next() 方法,且该方法返回形如 { value: any, done: boolean } 的对象,它就是迭代器。数组、字符串、Map、Set 默认提供 [Symbol.iterator]() 方法,调用后才得到真正的迭代器对象。
常见错误是直接对数组调用 next():[1,2,3].next() 会报 TypeError: undefined is not a function —— 因为数组本身不是迭代器,得先调用 [1,2,3][Symbol.iterator]() 才行。
实际使用中,for...of、解构赋值(const [a, b] = arr)、扩展运算符([...arr])都会自动调用 [Symbol.iterator] 并消费迭代器,你通常不需要手动写 next() 调用链。
Generator 函数本质是迭代器工厂
function* 声明的 generator 函数不立即执行,而是返回一个迭代器对象。每次调用它的 next(),函数体从上次暂停处(yield)继续运行,直到下一个 yield 或函数结束。
立即学习“Java免费学习笔记(深入)”;
关键点:
-
yield后面的表达式只在next()被调用时求值,支持惰性计算 -
next()可传参,该参数会成为上一个yield表达式的返回值(常用于双向通信) - generator 函数内部可使用
throw()和return()控制流程,但多数场景只需next()
示例:
function* countdown(n) {
while (n > 0) yield n--;
}
const it = countdown(3);
it.next(); // { value: 3, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 1, done: false }
it.next(); // { value: undefined, done: true }
Generator 真正有用的三个场景
别把它当“高级 for 循环”用。generator 的价值在于**状态保持 + 暂停恢复 + 异步建模**:
- 无限序列生成:比如斐波那契、素数筛,用普通函数必须预分配数组;generator 可按需产出,内存零压力
-
异步流程控制(ES2017 前):配合
co或手写 runner,把yield Promise当作await用(注意:现在应优先用async/await) -
状态机封装:比如一个分步骤表单校验器,每步
yield校验结果,外部用next()推进,比一堆回调或 Promise 链更直观
容易忽略的是:generator 函数返回的迭代器对象本身是可遍历的,所以也能被 for...of 消费 —— 这让它的使用边界变得很自然,不用纠结“该不该手动调 next”。
为什么不能用普通函数模拟 generator
核心在于**执行上下文不可恢复**。普通函数一旦 return,栈帧销毁,局部变量全丢;而 generator 函数被 yield 暂停时,整个执行上下文(作用域链、变量、指令指针)都被保留下来,下次 next() 时原样恢复。
这意味着你无法靠闭包 + 计数器安全复现 generator 行为:比如多次调用同一 generator 实例,每次都是独立状态;但闭包模拟的“迭代器”若没做深拷贝或重置逻辑,状态会互相污染。
还有兼容性细节:generator 是 ES6+ 特性,IE 完全不支持;若需兼容旧环境,必须 Babel 编译(转成基于 regeneratorRuntime 的状态机),而这个 runtime 本身有体积和性能开销——不是所有“看起来像迭代”的地方都值得上 generator。











