generator函数是 es6 提供的新特性,它的最大特点是:控制函数的执行。让我们从网上最火的一个例子来看:

function* foo(x) {
    var y = 2 * (yield x + 1);
    var z = yield y / 3;
    return x + y + z;
}
var b = foo(5);
b.next(); // { value:6, done:false }
b.next(12); // { value:8, done:false }
b.next(13); // { value:42, done:true }
1
2
3
4
5
6
7
8
9

通俗的解释下为什么会有这种输出:

  1. 给函数 foo 传入参数 5,但由于它是 generator,所以执行到第一个 yield 前就停止了。
  2. 第一次调用 next(),这次传入的参数会被忽略暂停**。
  3. 第二次调用 next(12),传入的参数会被当作上一个 yield 表达式的返回值。因此,y = 2 * 12 = 24。执行到第二个 yield,返回其后的表达式的值 24 / 3 = 8。然后函数在此处暂停。
  4. 第三次调用 next(13),没有 yield,只剩 return 了,按照正常函数那样返回 return 的表达式的值,并且donetrue

难点:在于为什么最后的value是 42 呢?

首先,x的值是刚开始调用 foo 函数传入的 5。而最后传入的 13 被当作第二个 yield 的返回值,所以z的值是 13。对于y的值,我们在前面第三步中已经计算出来了,就是 24。

所以,x + y + z = 5 + 24 + 13 = 42

看懂了上面的分析,再看下面这段代码就很好理解了:

function* foo(x) {
    var y = 2 * (yield x + 1);
    var z = yield y / 3;
    return x + y + z;
}
var a = foo(5);
a.next(); // Object{value:6, done:false}
a.next(); // Object{value:NaN, done:false}
a.next(); // Object{value:NaN, done:true}
1
2
3
4
5
6
7
8
9

只有第一次调用 next 函数的时候,输出的 value 是 6。其他时候由于没有给 next 传入参数,因此 yield 的返回值都是undefined,进行运算后自然是NaN

来自: ES6中的generator和yield函数 | 心谭博客
作者:心谭
Star仓库:github