生成器函数(Generator Function) 的核心用法

104 阅读2分钟

首先看一个题目

generator() { 
    console.log('start'); 
    let a = yield 1; 
    console.log('a:', a); 
    let b = yield 2; 
    console.log('b:', b); return 3; 
} 

let gen = generator(); 
console.log(gen.next()); 
console.log(gen.next('hello')); 
console.log(gen.next('world'));

猜猜输出什么?

1. 生成器函数(Generator Function)

  • 通过 function* 声明,生成器函数可以 暂停执行 并在之后 恢复执行
  • 调用生成器函数(如 generator())不会立即执行函数体,而是返回一个 生成器对象gen),该对象遵守 迭代器协议

2. yield 关键字

  • yield 是生成器函数内部的暂停点,每次执行到 yield 时会返回右侧的值(如 yield 1 返回 1),并暂停函数执行。
  • 下次调用 gen.next() 时,函数从上次暂停处继续执行,直到遇到下一个 yield 或 return。 (如果next()有入参会怎样? 我们继续往下看)

3. 生成器对象的方法 next()

  • gen.next() 启动或恢复生成器函数的执行,返回一个对象 { value: any, done: boolean }

    • valueyield 或 return 的值。
    • done:生成器函数是否执行完毕(true表示结束)。
  • gen.next(arg) 可以传递参数(如 'hello'),该参数会 作为上一个 yield 表达式的返回值 赋值给变量(如 a)。

题目解答

执行流程分析

  • 第一次 gen.next()

    • 执行到 yield 1,返回 { value: 1, done: false },暂停。
    • 控制台输出 'start'
  • 第二次 gen.next('hello')

    • 将 'hello' 赋值给 a(即 let a = 'hello')。
    • 执行到 yield 2,返回 { value: 2, done: false },暂停。
    • 控制台输出 'a: hello'
  • 第三次 gen.next('world')

    • 将 'world' 赋值给 b(即 let b = 'world')。
    • 执行到 return 3,返回 { value: 3, done: true },生成器结束。
    • 控制台输出 'b: world'
答案
start
{ value: 1, done: false }
a: hello
{ value: 2, done: false }
b: world
{ value: 3, done: true }

关键理解点

  • 暂停与恢复:生成器函数通过 yield 暂停,通过 next() 恢复。
  • 双向通信next(arg) 的参数会成为上一个 yield 的返回值,实现外部向生成器内部传递数据。
  • 迭代器协议:生成器对象可用于 for...of 循环或解构,因为它实现了 [Symbol.iterator]