generator

用函数编写一个产生斐波那契数列的函数,可以这么写:

function fib(max) {
    var
        t,
        a = 0,
        b = 1,
        arr = [0, 1];
    while (arr.length < max) {
        t = a + b;
        a = b;
        b = t;
        arr.push(t);
    }
    return arr;
}

fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

函数只能返回一次,所以必须返回一个 Array。但是,如果换成 generator,就可以一次返回一个数,不断返回多次。用 generator 改写如下:

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 1;
    while (n < max) {
        yield a;
        t = a + b;
        a = b;
        b = t;
        n ++;
    }
    return a;
}

直接调用试试:

fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}

直接调用一个 generator 和调用函数不一样,fib(5) 仅仅是创建了一个 generator 对象,还没有去执行它。

调用 generator 对象有两个方法,一是不断地调用 generator 对象的 next() 方法:

var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: true}

next() 方法会执行 generator 的代码,然后,每次遇到 yield x; 就返回一个对象 {value: x, done: true/false},然后“暂停”。返回的 value 就是 yield 的返回值。

done 表示这个 generator 是否已经执行结束了。如果 donetrue,则 value 就是 return 的返回值。

当执行到 donetrue 时,这个 generator 对象就已经全部执行完毕,不要再继续调用 next() 了。

第二个方法是直接用 for ... of 循环迭代 generator 对象,这种方式不需要我们自己判断 done

for (var x of fib(5)) {
    console.log(x); // 依次输出0, 1, 1, 2, 3
}

你可能感兴趣的:(generator)