(Generator 函数的语法)

Generator 函数的语法

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

形式上,Generator 函数是一个普通函数,但是有两个特征。一是, function  关键字与函数名之
间有一个星号;二是,函数体内部使用 yield  表达式,定义不同的内部状态( yield  在英语里的
意思就是“产出”)。

1.  function* helloWorldGenerator() {
2.  yield 'hello';
3.  yield 'world';
4.  return 'ending';
5.  }
6.
7.  var hw = helloWorldGenerator();

上面代码定义了一个 Generator 函数 helloWorldGenerator  ,它内部有两个 yield  表达式
( hello  和 world  ),即该函数有三个状态:hello,world 和 return 语句(结束执行)。


然后,Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的
指针对象,也就是上一章介绍的遍历器对象(Iterator Object)。


下一步,必须调用遍历器对象的 next  方法,使得指针移向下一个状态。也就是说,每次调
用 next  方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个 yield  表
达式(或 return  语句)为止。换言之,Generator 函数是分段执行的, yield  表达式是暂停执
行的标记,而 next  方法可以恢复执行。

1.  hw.next()
2.  // { value: 'hello', done: false }
3.
4.  hw.next()
5.  // { value: 'world', done: false }
6.
7.  hw.next()
8.  // { value: 'ending', done: true }
9.
10.  hw.next()
11.  // { value: undefined, done: true }

第三次调用,Generator 函数从上次 yield  表达式停下的地方,一直执行到 return  语句(如果
没有 return  语句,就执行到函数结束)。 next  方法返回的对象的 value  属性,就是紧跟
在 return  语句后面的表达式的值(如果没有 return  语句,则 value  属性的值
为 undefined  ), done  属性的值 true  ,表示遍历已经结束。


第四次调用,此时 Generator 函数已经运行完毕, next  方法返回对象的 value  属性
为 undefined  , done  属性为 true  。以后再调用 next  方法,返回的都是这个值。


总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以
后,每次调用遍历器对象的 next  方法,就会返回一个有着 value  和 done  两个属性的对
象。 value  属性表示当前的内部状态的值,是 yield  表达式后面那个表达式的值; done  属性
是一个布尔值,表示是否遍历结束。

ES6 没有规定, function  关键字与函数名之间的星号,写在哪个位置。这导致下面的写法都能通
过。

1.  function * foo(x, y) { ··· }
2.  function *foo(x, y) { ··· }
3.  function* foo(x, y) { ··· }
4.  function*foo(x, y) { ··· }

由于 Generator 函数仍然是普通函数,所以一般的写法是上面的第三种,即星号紧跟
在 function  关键字后面。本书也采用这种写法。

yield 表达式

由于 Generator 函数返回的遍历器对象,只有调用 next  方法才会遍历下一个内部状态,所以其
实提供了一种可以暂停执行的函数。 yield  表达式就是暂停标志。

需要注意的是, yield  表达式后面的表达式,只有当调用 next  方法、内部指针指向该语句时才会
执行,因此等于为 JavaScript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。

1.  function* gen() {
2.  yield 123 + 456;
3.  }

上面代码中, yield  后面的表达式 123 + 456  ,不会立即求值,只会在 next  方法将指针移到
这一句时,才会求值。

Generator 函数可以不用 yield  表达式,这时就变成了一个单纯的暂缓执行函数。

1.  function* f() {
2.  console.log('执行了!')
3.  }
4.
5.  var generator = f();
6.
7.  setTimeout(function () {
8.  generator.next()
9.  }, 2000);

上面代码中,函数 f  如果是普通函数,在为变量 generator  赋值时就会执行。但是,函数 f  是
一个 Generator 函数,就变成只有调用 next  方法时,函数 f  才会执行。

另外需要注意, yield  表达式只能用在 Generator 函数里面,用在其他地方都会报错。

1.  (function (){
2.  yield 1;
3.  })()
4.  // SyntaxError: Unexpected number

上面代码在一个普通函数中使用 yield  表达式,结果产生一个句法错误。

for…of 循环

for...of  循环可以自动遍历 Generator 函数运行时生成的 Iterator  对象,且此时不再需要调用 next  方法。

1.  function* foo() {
2.  yield 1;
3.  yield 2;
4.  yield 3;
5.  yield 4;
6.  yield 5;
7.  return 6;
8.  }
9.
10.  for (let v of foo()) {
11.  console.log(v);
12.  }
13.  // 1 2 3 4 5

2021-05-21  17:26:39

posted @ 2021-05-21 17:27  铁打的代码流水的bug  阅读(103)  评论(0)    收藏  举报