首先看一个题目
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 }:value:yield或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]。