关于JavaScript生成器generator和yield的一些理解

目录

综述

  Generator(生成器)函数是ES6提供的一种异步编程解决方案,而yield则是配合生成器函数使用的。


Generator函数

定义

  function* 声明(function关键字后跟一个星号)定义一个generator(生成器)函数,返回一个Generator对象。

语法

function* name([param[, param[, ... param]]]) { statements }
其中:

  • name
    函数名
  • param
    传入函数的参数名,一个函数至多可有255个参数。
  • statements
    函数的主体

注:ES6没有规定,function关键字与函数名之间的星号必须写在哪个位置,因此下面的写法都正确,但是还是推荐上述写法。

1
2
3
function * name([param[, param[, ... param]]]) { statements }
function *name([param[, param[, ... param]]]) { statements }
function*name([param[, param[, ... param]]]) { statements }

描述

  生成器是一种可以从中退出并在之后重新进入的函数。生成器的环境(绑定的变量)会在每次执行后被保存,下次进入时可继续使用。调用一个生成器函数并不马上执行它的主体,而是返回一个这个生成器函数的迭代器(iterator)对象。当这个迭代器的next()方法被调用时:

  • 生成器函数的主体会被执行直至第一个yield表达式,该表达式定义了迭代器返回的值;
  • 或者,被 yield*委派至另一个生成器函数。

next()方法返回一个对象,该对象有一个value属性,表示产出的值,和一个done属性,表示生成器是否已经产出了它最后的值。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
function* idMaker(){
var index = 0;
while(index<3)
yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
// ...

yield

定义

  yield 关键字用来暂停和继续一个生成器函数。

语法

yield [[expression]];

  • expression
    用作返回值. 如果忽略, 将返回 undefined .

描述

  yield关键字使生成器函数暂停执行,并返回跟在它后面的表达式的当前值。可以把它想成是return关键字的一个基于生成器的版本。yield 关键字实际返回一个对象,包含两个属性value和done。value属性为yield expression的值,done是一个布尔值用来指示生成器函数是否已经全部完成。
一旦在yield expression处暂停, 除非外部调用生成器的next()方法,否则生成器的代码将不能继续执行。这使得可以对生成器的执行以及渐进式的返回值进行直接控制。

示例

同上示例。


yield*

定义

  在生成器中,yield* 可以把需要yield的值委托给另外一个生成器或者其他任意的可迭代对象。

语法

yield* [[expression]];

  • expression
    任意的可迭代对象。

描述

 yield* 一个可迭代对象,就相当于把这个可迭代对象的所有迭代值分次yield出去。yield* 表达式本身的值就是当前可迭代对象迭代完毕(当done为true时)时的返回值。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function* g1() {
yield 2;
yield 3;
yield 4;
}

function* g2() {
yield 1;
yield* g1();
yield 5;
}

var iterator = g2();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

注意事项

  1. yield语句不能用在普通函数(即不带有*的function)中,否则会报错。
  2. Generator函数可以不用yield语句,这时就变成了一个单纯的暂缓执行函数。
  3. Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。
  4. 参考文档:阮一峰 ECMAScript6入门MDN官方文档