正经文章的地方

生成器与迭代器

一、定义

可迭代 iterable:一个包含可以在它的值上迭代的迭代器的对象。
这个对象必须支持一个函数,名称为专门的ES6符号值Symbol.iterator,调用时会返回一个迭代器。通常每次调用返回的都是新的迭代器,不过非必须。

迭代器:是一个定义良好的接口,用来从一个生产者一步步得到一系列值。
含有next()方法,每次从一个对象得到下一个值的时候就调用一下next()。

生成器:值的生产者。
生成器并不是iterable,执行了一个生成器,得到一个迭代器。
用*定义,yield暂停。

function *foo () { ... } // 生成器
var it = foo();          // 迭代器
it.next();               // 调用next生成值

生成器中的yield暂停并不阻塞整个程序,只会暂停生成器本身的代码,可以将异步回调写的看起来像是同步代码一样,实现了将异步作为实现细节抽象出去,只关注同步的任务流程。
另外,yield暂停也可以让代码捕捉到异步错误。

4.1.2 #6749 书后习题:

​​function step(gen) {
    var it = gen();
    var last;

    return function() {
        last = it.next(last).value;
        console.log("a:", a, ", b:", b);
        console.log("last:", last);
    };
}

function *foo() {
    a++;
    yield;
    b = b * a;
    a = (yield b) + 3;
}

function *bar() {
    b--;
    yield;
    a = (yield 8) + b;
    b = a * (yield 2);
}

var a = 1, b = 2;
var s1 = step(foo), s2 = step(bar);

s2(); // 1 1 undefined undefined,注意,last是一个闭包中的值,s1、s2要分开讨论
s2(); // 1 1 undefined 8
s1(); // 2 1 undefined 8
s2(); // 9 1 undefined 2
s1(); // 9 9 9 2
s1(); // 12 9 undefined 2
s2(); // 12 24 undefined undefined a值错误×
      // → 正解:a在此时已经有了,是9,yield 2的时候只是给后半部分赋值
      // 所以此时应该是9 * 2,而不是新的a得到12 * 2