一文搞懂ES6生成器函数:从语法到惰性求值的核心逻辑

部署运行你感兴趣的模型镜像

生成器函数(Generator Function)是 JavaScript(ES6+)、Python 等语言中一种特殊的函数,核心作用是 分步生成数据、按需产出结果,而非一次性返回所有值。它的核心特点是「暂停执行、惰性求值」,能有效节省内存(尤其处理大数据集时),并支持迭代器协议(可通过 for...of 循环遍历)。

一、核心本质

普通函数调用后会 一次性执行完毕并返回结果(或 undefined),执行过程中无法暂停;生成器函数调用后 不会立即执行,而是返回一个「生成器对象(Generator Object)」—— 这个对象既是「迭代器」(有 next() 方法),也是「可迭代对象」(可被 for...of 遍历)。只有通过调用生成器对象的 next() 方法,函数才会执行,直到遇到 yield 关键字暂停,将 yield 后的值作为「当前结果」返回;再次调用 next(),函数从暂停处继续执行,直到下一个 yield 或函数结束。

二、语法特征(以 JavaScript 为例)

  1. 函数声明时加 * 标记(function*);
  2. 函数体内用 yield 关键字「产出」数据(每次 yield 对应一次结果);
  3. 调用时直接写 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 值)

五、应用场景

  1. 处理大数据集 / 文件:逐行读取大文件、分批处理数据库查询结果(避免一次性加载所有数据);
  2. 生成无限序列:斐波那契数列、自增 ID 生成器等;
  3. 异步流程控制(JS 早期):在 async/await 普及前,生成器常与 co 库配合实现异步代码同步化(现在已被 async/await 替代,但原理相通);
  4. 迭代器封装:简化自定义可迭代对象的实现(无需手动写 Symbol.iterator 方法)。

总结

生成器函数的核心是「暂停 - 恢复」的执行机制和「惰性求值」的特性:

  • 普通函数:一次执行,返回所有结果;
  • 生成器函数:分步执行,按需返回结果,节省内存且支持灵活的双向通信。

它是处理「需要分步生成数据」场景的高效工具,也是理解迭代器、异步编程(如 async/await)的重要基础。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canjun_wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值