[ES6] Generator

Generator的语法

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。

下面代码定义了一个 Generator 函数testGenerator,它内部有两个yield表达式,即该函数有三个状态:a+1,a+2 和 a+3 。

function* testGenerator(a) {
  yield a + 1;
  yield a + 2;
  return a + 3;
}

var tg = testGenerator(2);

Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象。
接下来,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

tg.next()   // { value: 3, done: false }
tg.next(3)   // { value: 5, done: false }
tg.next(4)   // { value: 7, done: true }
tg.next(2)   // { value: undefined, done: true }

以下的定义都是被允许的,但是我们通常采用第一种写法

function* foo(x, y) { ··· }
function * foo(x, y) { ··· }
function *foo(x, y) { ··· }
function*foo(x, y) { ··· }

yield表达式

yield表达式只能用在Generator函数中,否则会报错。一下的代码把yield放在了forEach中,会报错,把forEach改成for循环即可。

var arr = [1, [[2, 3], 4], [5, 6]];

var flat = function* (a) {
  a.forEach(function (item) {
    if (typeof item !== 'number') {
      yield* flat(item); //会报错
    } else {
      yield item;
    }
  });
};

for (var f of flat(arr)){
  console.log(f);
}

yield表达式如果用在另一个表达式之中,必须放在圆括号里面。

function* demo() {
  console.log('Hello' + yield); // SyntaxError
  console.log('Hello' + yield 123); // SyntaxError
  console.log('Hello' + (yield)); // OK
  console.log('Hello' + (yield 123)); // OK
}

next方法

next方法可以带一个参数,该参数就会被当作Generator函数中,上一个yield表达式的返回值。
下面的代码中,第二次运行a.next()时候不带参数,导致 y 的值等于2 * undefined(即NaN),除以 3 以后还是NaN,因此返回对象的value属性也等于NaN。第三次运行a.next()时候不带参数,所以z等于undefined,返回对象的value属性等于5 + NaN + undefined,即NaN。
如果向next方法提供参数,返回结果就完全不一样了。上面代码第一次调用b.next()时,返回x+1的值6;第二次调用b.next(),将上一次yield表达式的值设为12,因此y等于24,返回y / 3的值8;第三次调用b.next(),将上一次yield表达式的值设为13,因此z等于13,这时x等于5,y等于24,所以return语句的值等于42。

function* demo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = demo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = demo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 简介 基本概念 Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍...
    呼呼哥阅读 1,097评论 0 4
  • 1.基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细...
    lhdoeo阅读 373评论 0 1
  • 本文作者就是我,简书的microkof。如果您觉得本文对您的工作有意义,产生了不可估量的价值,那么请您不吝打赏我,...
    microkof阅读 23,793评论 16 78
  • 在此处先列下本篇文章的主要内容 简介 next方法的参数 for...of循环 Generator.prototy...
    醉生夢死阅读 1,463评论 3 8
  • Generator 函数的语法 简介 基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语...
    站在大神的肩膀上看世界阅读 4,211评论 0 6