目录

一、核心本质

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

三、关键特性

1. 惰性求值(按需生成)

2. next() 可传参(给上一个 yield 赋值)

3. 可被 for...of 遍历

4. yield* 委托遍历

四、Python中的生成器函数(补充)

五、应用场景

六、生成器函数总结


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

一、核心本质

普通函数调用后会 一次性执行完毕并返回结果(或 undefined),执行过程中无法暂停;生成器函数调用后 不会立即执行,而是返回一个「生成器对象(Generator Object)」—— 这个对象既是「迭代器」(有 next() 方法),也是「可迭代对象」(可被 for...of 遍历)。

只有通过调用生成器对象的 next() 方法,函数才会执行,直到遇到 yield 关键字暂停(返回一个包含 value 和 done 属性的对象),将 yield 后的值作为「当前结果」返回;再次调用 next(),函数从暂停处继续执行,直到下一个 yield 或函数结束。

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

  • 函数声明时加 * 标记(function*);
  • 函数体内用 yield 关键字「产出」数据(每次 yield 对应一次结果);
  • 调用时直接写 fn(),返回生成器对象(而非执行函数体)。
  • 生成器函数返回的迭代器对象符合迭代器协议,包含next()、return()和throw()方法。

基础示例:

// 定义生成器函数
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() {
  // 第一次 next() 产出问题,暂停;name 接收下一次 next() 的参数
  const name = yield "你好,请问你叫什么?"; 
  // 第二次 next() 产出问候,暂停
  yield `你好,${name}!`; 
}
 
const talk = talkGenerator();
// { value: "你好,请问你叫什么?", done: false }
console.log(talk.next().value); 
// { value: "你好,小明!", done: false }
console.log(talk.next("小明").value); 

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 生成器等;

// 生成斐波那契数列:
function* fibonacci() {
  let [a, b] = [0, 1];
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1

3、异步流程控制(JS 早期):在 async/await 普及前,生成器常与 co 库配合实现异步代码同步化(现在已被 async/await 替代,但原理相通);

// 异步流程控制生成器可用于简化异步代码,结合yield暂停特性,实现类似同步的异步操作写法。
function* fetchUser() {
  const response = yield fetch('https://api.example.com/user');
  const data = yield response.json();
  return data;
}

const generator = fetchUser();
const promise = generator.next().value;
promise.then(response => {
  return generator.next(response).value;
}).then(data => {
  console.log(generator.next(data).value);
});

4、迭代器封装:简化自定义可迭代对象的实现(无需手动写 Symbol.iterator 方法)。

5、实现状态机:生成器天然适合实现状态机逻辑,每个yield代表一个状态节点

function* trafficLight() {
  while (true) {
    yield 'red';
    yield 'yellow';
    yield 'green';
  }
}

const light = trafficLight();
light.next().value; // 'red'
light.next().value; // 'yellow'

六、生成器函数总结

生成器函数使用 function* 语法定义,它是一种特殊的函数,执行时不会立即运行其内部代码,而是返回一个生成器对象(该对象同时是一个迭代器)。通过调用这个生成器对象的 next() 方法,函数会执行到遇到下一个 yield 关键字时暂停,并返回一个包含 valuedone 属性的对象。这使得生成器函数能够暂停和恢复执行,为异步编程和自定义迭代逻辑提供了强大的工具。

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

  • 普通函数:一次执行,返回所有结果;
  • 生成器函数:分步执行,按需返回结果,节省内存且支持灵活的双向通信。
  • 它是处理「需要分步生成数据」场景的高效工具,也是理解迭代器、异步编程(如 async/await)的重要基础。

注意事项

  1. 执行顺序:生成器函数在首次调用next()时才开始执行,而非声明时。
  2. 错误处理:可通过generator.throw()向生成器内部抛出错误,需在函数体内用try/catch捕获。
  3. 资源清理:若提前终止生成器,应调用generator.return()释放资源。
  4. 兼容性:旧版浏览器需通过Babel等工具转译。

优化建议

  •  避免频繁创建:对性能敏感场景,复用生成器对象而非重复创建。
  • 结合for...of:遍历生成器时使用for...of语法更简洁: 
for (const value of fibonacci()) {
  if (value > 100) break;
  console.log(value);
}
  • 与Promise配合:使用库如co或异步生成器(ES2018)进一步简化异步代码:
async function* asyncGenerator() {
  yield await Promise.resolve(1);
}

参考资料: 

ES6的迭代器(Iterator)和生成器(Generator) | MDN:function* ES6生成器函数详解 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐