迭代器和生成器-生成器(Generator)

219 阅读3分钟

应用场景

简化迭代器的编写。

什么是生成器?

是一个通过构造函数Generator创建的对象。生成器既是一个迭代器,又是一个可迭代对象。

如何创建生成器?

生成器的创建,必须使用生成器函数(Generator Function)

// 这是一个生成器函数,该函数一定返回一个生成器
function *method(){

}

这是得到生成器的唯一途径。

举例:

function *method(){

}
const generator = method();
console.log(generator)

有next方法,又有知名符号,说明这是一个迭代器,所以:

  1. 能调用.next()方法;
  2. 能用for-of循环

生成器函数内部是如何执行的?

生成器函数内部是为了给生成器的每次迭代提供数据的。

先看一个例子:

function *test(){
    console.log('a')
}
const generator = test();
// 没有输出a,因为test函数并没有执行

由此, 我们要消除一个误解:

生成器函数(上例中的test)内部并不执行,调用函数只是用来创建生成器(上例中的generator)。

那么,生成器函数内部到底是如何运行的?

生成器函数内部是为了给生成器的每次迭代提供数据的。

分析:

  1. 得到生成器是为了迭代(不断拿到下一个数据)

  2. 函数里面是给生成器每一次迭代提供数据的

    const generator = test();
    // 该生成器没有迭代
    // 生成器调用next()才叫迭代;不调用不叫迭代,所以迭代函数没有运行
    
  3. 那么生成器函数里面是如何提供数据

    • 每次调用生成器的next方法,将导致生成器函数运行到下一个yield关键字位置。
    • yield是一个关键字,该关键字只能在生成器函数内部使用,表达‘产生’一个迭代数据的意思

    举例说明:

    function *test(){
        console.log('第一次运行');
        yield 1;
        console.log('第二次运行');
        yield 2;
        console.log('第三次运行');
    }
    const generator = test();
    console.log(generator.next());
    
     分析:
     1. generator本身不执行,调用next方法才执行
    
     2. 第一次调用next方法,得到:
    

    value是yield的值;函数还没运行完,所以done为false,当函数运行完done为true

    1. 继续调用next方法,得到:

练习:编写一个生成器

const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];

function *createIterator(arr){
    for(const item of arr){
        yield item;
    }
}
const iter1 = createIterator(arr1);
const iter2 = createIterator(arr2);

有哪些需要注意的细节?

  1. 生成器可以有返回值,返回值出现在第一次done为true的value属性中;

  2. 调用生成器next方法时,可以传递参数,传递的参数会交给yield表达式的返回值

    举例说明:

    function *test(){
        let info = yield 1;
        console.log(info);
        info = yield 2 + info;
        console.log(info);
    }
    const generator = test();
    

    分析:

    1. 第一次调用next卡在yield1;
    2. 此时调用next方法,传递一个参数:5;
    3. 此时info为5;
    4. 此时yield为7,又卡在了yield;
    5. 继续调用next,但是不传参数;
    6. 此时info为undefined
  3. 第一次调用next方法时,传参没有任何意义;

  4. 在生成器内部,可以调用其他生成器函数,但是要注意加上*号

生成器的其他API

  • return方法:调用该方法,可以提前结束生成器函数,从而提前让整个迭代过程结束;
  • throw方法:调用该方法,可以在生成器中产生一个错误。