生成器函数(Generator Function)是 JavaScript(ES6+)、Python 等语言中一种特殊的函数,核心作用是 分步生成数据、按需产出结果,而非一次性返回所有值。它的核心特点是「暂停执行、惰性求值」,能有效节省内存(尤其处理大数据集时),并支持迭代器协议(可通过 for...of 循环遍历)。
一、核心本质
普通函数调用后会 一次性执行完毕并返回结果(或 undefined),执行过程中无法暂停;生成器函数调用后 不会立即执行,而是返回一个「生成器对象(Generator Object)」—— 这个对象既是「迭代器」(有 next() 方法),也是「可迭代对象」(可被 for...of 遍历)。只有通过调用生成器对象的 next() 方法,函数才会执行,直到遇到 yield 关键字暂停,将 yield 后的值作为「当前结果」返回;再次调用 next(),函数从暂停处继续执行,直到下一个 yield 或函数结束。
二、语法特征(以 JavaScript 为例)
- 函数声明时加
*标记(function*); - 函数体内用
yield关键字「产出」数据(每次yield对应一次结果); - 调用时直接写
fn(),返回生成器对象(而非执行函数体)。
基础示例:
// 定义生成器函数
function* numberGenerator() {
yield 1; // 第一次调用 next() 产出 1,暂停
yield 2; // 第二次调用 next() 产出 2,暂停
yield 3; // 第三次调用 next() 产出 3,暂停
return "结束"; // 第四次调用 next(),返回 return 值,函数终止
}
// 调用生成器函数:返回生成器对象(函数体未执行)
const generator = numberGenerator();
// 调用 next() 触发执行,返回 { value: 产出值, done: 是否结束 }
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: false }
console.log(generator.next()); // { value: "结束", done: true }
console.log(generator.next()); // { value: undefined, done: true }(后续调用均返回此结果)
三、关键特性
1. 惰性求值(按需生成)
生成器不会一次性计算所有结果,只有当调用 next() 时才会生成下一个值。适合处理 大数据集、无限序列(如斐波那契数列),避免一次性加载所有数据导致内存溢出:
// 生成无限递增的整数序列(不会占用大量内存)
function* infiniteGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const infinite = infiniteGenerator();
console.log(infinite.next().value); // 0
console.log(infinite.next().value); // 1
console.log(infinite.next().value); // 2
// 按需获取,永远不会耗尽(但不会占满内存)
2. next() 可传参(给上一个 yield 赋值)
next(arg) 的参数会作为「上一个 yield 表达式的返回值」,实现「双向通信」(生成器产出值,调用方传递参数):
function* talkGenerator() {
const name = yield "你好,请问你叫什么?"; // 第一次 next() 产出问题,暂停;name 接收下一次 next() 的参数
yield `你好,${name}!`; // 第二次 next() 产出问候,暂停
}
const talk = talkGenerator();
console.log(talk.next().value); // { value: "你好,请问你叫什么?", done: false }
console.log(talk.next("小明").value); // { value: "你好,小明!", done: false }
3. 可被 for...of 遍历
生成器对象是可迭代对象,for...of 会自动调用 next(),直到 done: true(会忽略 return 的值):
function* fruitGenerator() {
yield "苹果";
yield "香蕉";
yield "橙子";
return "遍历结束"; // for...of 会忽略此值
}
// 遍历生成器
for (const fruit of fruitGenerator()) {
console.log(fruit); // 输出:苹果、香蕉、橙子(无 "遍历结束")
}
4. yield* 委托遍历
yield* 可以将遍历权委托给另一个生成器(或可迭代对象,如数组),简化嵌套生成器的调用:
function* subGenerator() {
yield 3;
yield 4;
}
function* mainGenerator() {
yield 1;
yield 2;
yield* subGenerator(); // 委托给 subGenerator,相当于 yield 3、yield 4
yield 5;
}
for (const num of mainGenerator()) {
console.log(num); // 输出:1、2、3、4、5
}
四、Python 中的生成器函数(补充)
Python 中生成器函数的逻辑与 JS 一致,语法差异:
- 无需
function*,直接用def定义; - 用
yield产出值,调用后返回生成器对象; - 同样支持
next()调用和for...of(Python 中是for...in)遍历。
Python 示例:
def number_generator():
yield 1
yield 2
yield 3
return "结束"
# 调用生成器函数,返回生成器对象
gen = number_generator()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# print(next(gen)) # 抛出 StopIteration 异常,异常值为 "结束"
# for...in 遍历(自动处理 StopIteration)
for num in number_generator():
print(num) # 1、2、3(忽略 return 值)
五、应用场景
- 处理大数据集 / 文件:逐行读取大文件、分批处理数据库查询结果(避免一次性加载所有数据);
- 生成无限序列:斐波那契数列、自增 ID 生成器等;
- 异步流程控制(JS 早期):在
async/await普及前,生成器常与co库配合实现异步代码同步化(现在已被async/await替代,但原理相通); - 迭代器封装:简化自定义可迭代对象的实现(无需手动写
Symbol.iterator方法)。
总结
生成器函数的核心是「暂停 - 恢复」的执行机制和「惰性求值」的特性:
- 普通函数:一次执行,返回所有结果;
- 生成器函数:分步执行,按需返回结果,节省内存且支持灵活的双向通信。
它是处理「需要分步生成数据」场景的高效工具,也是理解迭代器、异步编程(如 async/await)的重要基础。

1万+

被折叠的 条评论
为什么被折叠?



