迭代器和生成器是JavaScript中实现懒求值与可中断执行的底层机制,核心是next()返回{value, done}对象;对象要可迭代,必须实现[Symbol.iterator]()方法并返回含next()的迭代器对象。

迭代器和生成器不是语法糖,而是 JavaScript 中实现“懒求值”和“可中断执行”的底层机制;它们的核心契约是 next() 方法返回 { value, done } 对象,而不是“自动循环”或“类似 for...of 的便利写法”。
迭代器对象必须实现 [Symbol.iterator]() 方法
一个对象要能被 for...of、Array.from()、展开运算符等消费,它必须提供一个返回迭代器对象的 [Symbol.iterator] 方法。这个迭代器对象本身必须有 next() 方法。
常见错误是只实现了 next(),但没把该方法挂到 [Symbol.iterator] 上:
const badIterator = {
next() { return { value: 1, done: false }; }
};
// ❌ for (let x of badIterator) {} → TypeError: badIterator is not iterable正确写法:
立即学习“Java免费学习笔记(深入)”;
const goodIterable = {
[Symbol.iterator]() {
let i = 0;
return {
next() {
if (i < 3) return { value: i++, done: false };
return { value: undefined, done: true };
}
};
}
};
// ✅ for (let x of goodIterable) {} 正常运行
function* 声明的是生成器函数,调用后返回生成器对象
生成器函数不是普通函数:它不立即执行,调用后只返回一个生成器对象(即符合迭代器协议的对象),该对象同时是可迭代的(自带 [Symbol.iterator] === self)和可遍历的(有 next()、return()、throw())。
关键点:
云枫工作室企业网站源代码(.net)Version 4.0 是云枫工作室基于.net环境独立开发的一套适用于企业使用的企业网站系统。.net+access.网站使用了模板动态生成静态页面技术,前台页面是生成纯静态的。网站包括了信息管理,产品管理,新闻管理和在线留言。可以在后台设置网站名称,标题,关键字和网站描述。配置说明:服务器空间需要支持.net2.0,还要有可写的权限(这个是必要的,因为网站前
-
yield暂停执行并产出值,下次next()从暂停处继续 -
return语句会触发done: true,且其值成为最后一次next()的value - 生成器对象不可重用:一旦
done: true,后续所有next()都返回{ value: undefined, done: true }
function* count() {
yield 1;
yield 2;
return 'done';
}
const gen = count();
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: 'done', done: true }
gen.next(); // { value: undefined, done: true } —— 不再恢复
yield* 是委托,不是调用;它展开的是可迭代对象,不是函数调用结果
yield* 后面跟的必须是一个可迭代对象(即具有 [Symbol.iterator] 的东西)。它不是“执行函数然后 yield 结果”,而是“把控制权交给那个迭代器,逐个 yield 它产出的值”。
容易踩的坑:
-
yield* someArray✅(数组可迭代) -
yield* someGenerator()✅(生成器对象可迭代) -
yield* someFunction❌(函数本身不可迭代,除非它返回可迭代对象) -
yield* Promise.resolve([1,2])❌(Promise 不可迭代,即使 resolve 的是数组)
function* nums() {
yield* [10, 20];
yield* (function* () { yield 30; })();
}
Array.from(nums()); // [10, 20, 30]生成器内部的 this 绑定和错误传播需手动处理
生成器函数中没有 this 绑定(严格模式下为 undefined),且 try/catch 无法捕获外部注入的错误(如 gen.throw(e))——必须在生成器内部用 try/catch 显式包裹 yield 表达式。
另一个隐性成本:生成器对象保留完整执行上下文(闭包、暂停点),内存占用比普通迭代器高;高频短生命周期场景(如每次请求新建一个)要注意泄漏风险。
function* risky() {
const data = new Array(1000000).fill('x'); // 大闭包
try {
yield 'start';
} catch (e) {
console.log('caught:', e.message); // ✅ 只有这里才能捕获 gen.throw()
}
}真正难的不是写出 yield,而是判断何时不该用生成器:比如数据已全部在内存、无需暂停、不涉及异步协调时,一个简单数组或 for 循环更直接,也更容易被 JS 引擎优化。









