JavaScript中generator可天然实现数组遍历的惰性求值,通过yield逐个产出结果,避免预计算;但需避免JSON.stringify、Array.from等导致热执行的操作。

JavaScript 数组遍历配合 generator 可以天然实现惰性求值——generator 函数返回的迭代器只在每次 next() 调用时才计算下一个值,不预先执行全部逻辑,内存友好且可中断。
用 generator 封装数组遍历逻辑
把传统 for 或 forEach 改写为 function*,用 yield 逐个产出元素或处理结果:
function* mapLazy(arr, fn) {
for (let i = 0; i < arr.length; i++) {
yield fn(arr[i], i, arr);
}
}
<p>const nums = [1, 2, 3, 4, 5];
const doubled = mapLazy(nums, x => x * 2);</p><p>doubled.next(); // { value: 2, done: false }
doubled.next(); // { value: 4, done: false }
// 后续值尚未计算链式组合多个惰性操作
filter、map、take 等操作都可写成 generator,彼此嵌套调用,仍保持惰性——只有真正消费时才层层触发:
function* filterLazy(arr, predicate) {
for (const item of arr) {
if (predicate(item)) yield item;
}
}
<p>function* takeLazy(iter, n) {
let count = 0;
for (const item of iter) {
if (count >= n) break;
yield item;
count++;
}
}</p><p>// 组合:取前 2 个偶数(不生成整个中间数组)
const result = takeLazy(
filterLazy(mapLazy([1, 2, 3, 4, 5, 6], x => x * 2), x => x % 4 === 0),
2
);</p><p>Array.from(result); // [4, 8]与内置迭代方法(如 Symbol.iterator)无缝协作
generator 函数默认返回符合迭代协议的对象,可直接用于 for...of、扩展运算符、Array.from 等,但它们仍按需执行:
-
for (const x of mapLazy(arr, fn)) { ... }—— 每次循环只 yield 一个 -
[...mapLazy(arr, fn)]—— 看似“立即”,实则底层仍逐次调用next() -
Array.from(mapLazy(arr, fn), x => x + 1)—— 映射发生在展开过程中
注意边界:避免意外的“热”执行
generator 惰性依赖于不提前遍历。以下情况会破坏惰性:
- 把 generator 直接传给非迭代友好的 API(如
JSON.stringify(gen)) - 在 generator 内部预计算整个数组再
yield*(应改用逐个yield) - 用
Array.from(gen)后又反复使用该数组——它已转为热数据,generator 本身被消耗完毕
generator 是 JS 原生支持惰性求值最轻量、最标准的方式,无需第三方库,搭配数组遍历逻辑清晰、组合灵活、性能可控。


















