当前位置: 首页 > news >正文

JavaScript中的生成器函数详解

在 JavaScript 中,生成器函数 Generator Function 是一种特殊的函数,它允许你在函数执行过程中暂停和恢复。生成器函数通过 function* 语法定义,并使用 yield 关键字来控制函数的执行流程。生成器函数返回一个生成器对象,该对象遵循迭代器协议,可以逐步生成值。

以下是生成器函数的详细解析:

1. 基本语法

生成器函数使用 function* 定义,函数体内可以使用 yield 关键字来暂停函数的执行并返回一个值。

function* myGenerator() {yield 1;yield 2;yield 3;
}

function*:定义生成器函数的关键字。

yield:暂停函数执行并返回一个值。每次调用生成器对象的 next() 方法时,函数会从上次暂停的地方继续执行。

2. 生成器对象

生成器函数调用时不会立即执行函数体,而是返回一个生成器对象。这个生成器对象是一个迭代器,可以通过 next() 方法逐步执行生成器函数。

const gen = myGenerator();console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }

next():恢复生成器函数的执行,直到遇到下一个 yield 或函数结束。

返回一个对象,包含两个属性:

value:yield 表达式的值。

done:布尔值,表示生成器函数是否已经执行完毕。

3. yield 关键字

yield 是生成器函数的核心关键字,它的作用如下:

1. 暂停函数执行:当生成器函数执行到 yield 时,会暂停执行并返回 yield 后面的值;

2. 恢复函数执行:当调用生成器对象的 next() 方法时,函数会从上次暂停的地方继续执行,直到遇到下一个 yield 或函数结束;

function* myGenerator() {yield "Hello";yield "World";
}const gen = myGenerator();console.log(gen.next().value); // 'Hello'
console.log(gen.next().value); // 'World'
console.log(gen.next().done);  // true

4. yield* 表达式

yield* 用于委托给另一个生成器或可迭代对象(如数组、字符串等)。它允许在一个生成器函数中调用另一个生成器函数。

function* generator1() {yield 1;yield 2;
}function* generator2() {yield* generator1(); // 委托给 generator1yield 3;
}const gen = generator2();console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
console.log(gen.next().done); // true

5. 生成器函数的特性

5.1. 惰性求值

生成器函数是惰性的,只有在调用 next() 时才会执行。这使得生成器非常适合处理大量数据或无限序列。

function* infiniteSequence() {let i = 0;while (true) {yield i++;}
}const gen = infiniteSequence();console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// 可以无限调用

5.2. 双向通信

生成器函数不仅可以通过 yield 返回值,还可以通过 next() 方法接收外部传入的值。

function* generator() {const x = yield "Hello";yield x;
}const gen = generator();console.log(gen.next().value); // 'Hello'
console.log(gen.next(42).value); // 42

第一次调用 next() 时,生成器函数执行到 yield 'Hello' 并暂停。

第二次调用 next(42) 时,42 会作为 yield 表达式的值传入,生成器函数继续执行。

5.3. 提前终止

生成器对象提供了 return() 和 throw() 方法,可以提前终止生成器函数的执行。

return(value):终止生成器函数并返回指定的值。

throw(error):在生成器函数内部抛出一个错误。

function* generator() {yield 1;yield 2;yield 3;
}const gen = generator();console.log(gen.next().value); // 1
console.log(gen.return(42).value); // 42
console.log(gen.next().done); // true

6. 生成器函数的应用场景

6.1. 惰性求值

生成器函数非常适合处理大量数据或无限序列,因为它只在需要时生成值。

function* fibonacci() {let [prev, curr] = [0, 1];while (true) {yield curr;[prev, curr] = [curr, prev + curr];}
}const fib = fibonacci();console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5

6.2. 异步编程

在 async/await 出现之前,生成器函数常用于简化异步编程。通过结合 Promise 和生成器,可以实现类似于 async/await 的效果。

function* asyncGenerator() {const result1 = yield new Promise((resolve) =>setTimeout(() => resolve(1), 1000));const result2 = yield new Promise((resolve) =>setTimeout(() => resolve(2), 1000));return result1 + result2;
}function runGenerator(generator) {const gen = generator();function handle(result) {if (result.done) return Promise.resolve(result.value);return Promise.resolve(result.value).then((res) => {return handle(gen.next(res));});}return handle(gen.next());
}runGenerator(asyncGenerator).then(console.log); // 3

6.3. 自定义迭代器

生成器函数可以用于创建自定义迭代器,简化迭代器的实现。

const myIterable = {*[Symbol.iterator]() {yield 1;yield 2;yield 3;},
};for (const value of myIterable) {console.log(value); // 1, 2, 3
}

7. 总结

1. 生成器函数使用 function* 定义,通过 yield 暂停和恢复执行;

2. 生成器函数返回一个生成器对象,该对象是一个迭代器,可以通过 next() 方法逐步执行;

3. yield* 用于委托给另一个生成器或可迭代对象;

4. 生成器函数适用于惰性求值、异步编程和自定义迭代器等场景;

生成器函数提供了一种强大的控制流机制,使得你可以更灵活地管理函数的执行过程。


http://www.mrgr.cn/news/93905.html

相关文章:

  • 【CSS3】金丹篇
  • 微信小程序,自定义导航栏,搜索框滚动,搜索框过渡,滚动吸顶,吸顶导航栏,过渡动画,自定义tabbar
  • 【14】单片机编程核心技巧:整除运算与数位提取
  • VSCode 2025最新前端开发必备插件推荐汇总(提效指南)
  • Mac如何查看 IDEA 的日志文件
  • vulnhub靶场【digitalworld.local系列】的electrical靶机
  • OpenManus-通过源码方式本地运行OpenManus,含踩坑及处理方案,chrome.exe位置修改
  • 用python和Pygame库实现“跳过障碍”游戏
  • 从0开始的操作系统手搓教程33:挂载我们的文件系统
  • 若依RuoYi-Cloud-Plus微服务版(完整版)前后端部署
  • c语言笔记 getchar
  • 关于在electron(Nodejs)中使用 Napi 的简单记录
  • 多模态融合的分类、跨模态对齐的方法
  • 练习:关于静态路由,手工汇总,路由黑洞,缺省路由相关
  • vue3 + xlsx 实现导入导出表格,导出动态获取表头和数据
  • Linux 离线部署Ollama和DeepSeek-r1模型
  • 零基础掌握Linux SCP命令:5分钟实现高效文件传输,小白必看!
  • IO学习---->线程
  • QT系列教程(20) Qt 项目视图便捷类
  • 『PostgreSQL』PGSQL备份与还原实操指南