js--生成器gengrator总结

前言

  生成器gengrator是es6 新增的函数功能,它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 本文来总结一下JavaScript 中生成器的相关知识点。

正文

  1、 生成器是什么

  生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 生成器函数使用 function* 语法编写。 最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。 通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。

  2、 生成器实例( 通过yield 中断执行)

  (1)普通生成器函数

  调用生成器函数会产生一个类似于迭代器的生成器对象,。生成器对象一开始处于暂停执行(suspended)的状态。与迭代器相似,生成器对象也实现了 Iterator 接口,它们默认的迭代器是自引用的,因此具有 next() 方法。调用这个方法会让生成器开始执行,遇到yield关键字函数暂停,再次调用next()继续执行函数,yield并不回像return 一样立即结束函数,只是暂停这个生成器函数。

  注意:箭头函数不能用来定义生成器函数

        function* createIterator() {
            yield 1;
            yield 2;
            yield 3;
        }
        console.log(createIterator());// createIterator {<suspended>}
        console.log(createIterator()[Symbol.iterator]());// createIterator {<suspended>},因此可以通过生成器创建迭代器函数
        let iterator = createIterator()
        console.log(iterator.next().value);//1
        console.log(iterator.next().value);//2
        console.log(iterator.next().value);//3

  (2)函数表达式的生成器函数,使用函数表达式来创建一个生成器

        let myIterator = function* (items) {
            for (let i = 0; i < items.length; i++) {
                yield items[i]
            }
        }
        let myIterator1 = myIterator([1, 2, 3])
        console.log(myIterator1.next().value);//1
        console.log(myIterator1.next().value);//2
        console.log(myIterator1.next().value);//3

  (3)对象类型的生成器函数

        var obj = {
            createIterator: function* (item) {
                for (let i = 0; i < items.length; i++) {
                    yield items[i]
                }
            }
        }
        // 也可以
        var obj = {
            *createIterator(items) {
                for (let i = 0; i < items.length; i++) {
                    yield items[i]
                }
            }
        }

  生成器会在每个yield 语句后停止执行,在函数中停止执行的能力是极其强大的,yield 关键字指定了迭代器在被调用next的方法是应当按顺序返回的值,在没有调用next() 方法的时候,生成器函数里的的代码并不会执行,同时也可用通过return 返回生成器函数的返回值,如下:

        function* generatorFn() {
            console.log("start")
            yield 'foo';
            yield;
            yield 'bar';
            return 'baz';
        }
        let generatorObject = generatorFn();
        console.log(generatorObject.next()); //start   { done: false, value: 'foo' }
        console.log(generatorObject.next()); // { done: false, value: undefined }
        console.log(generatorObject.next()); // { done: false, value: 'bar' }
        console.log(generatorObject.next()); // { done: true, value: 'baz' }

  3、 yield关键字详解

  (1) yield 关键字可以和值或者是表达式在一起使用,因此可以通过生成器给迭代器添加项目,而不是机械化地将项目一个个列出。

        // for循环内部使用yield关键字
        function* createIterator2(items) {
            //let 块级作用域
            for (let i = 0; i < items.length; i++) {
                yield items[i]
            }
        }
        let iterator2 = createIterator2([1, 2, 3])
        console.log(iterator2.next());//{value:1,done:false}
        console.log(iterator2.next());//{value:2,done:false}
        console.log(iterator2.next());//{value:3,done:false}
        console.log(iterator2.next());//{value:undefined,done:true}

  注意 :yield 关键字只能用于生成器内部,用于其他位置会出现语法错误,即使在生成器内部的函数中也不行,下面的代码报错。

        // yield无法穿越函数边界,在一个嵌套函数中无法将值返回给包含它的函数
        // function* createIterator2(items) {
        //     items.forEach(item => {
        //         yield item +1//语法错误
        //     });
        // }

  (2) yield 关键字还可以作为函数的中间参数使用

  使用 yield 实现输入和输出, yield 关键字还可以作为函数的中间参数使用,上一次让生成器函数暂停的 yield 关键字会接收到传给 next() 方法的第一个值。第一次调用 next() 传入的值不会被使用,因为这一次调用是为了开始执行生成器函数

        function* generatorFn(initial) {
            console.log(initial);
            console.log(yield);
            console.log(yield);
        }
        let generatorObject = generatorFn('foo');
        generatorObject.next('bar'); // foo
        generatorObject.next('baz'); // baz
        generatorObject.next('qux'); // qux
        // yield 关键字可以同时用于输入和输出,如下
        function* generatorFn() {
            return yield 'foo';
        }
        let generatorObject = generatorFn();
        console.log(generatorObject.next()); // { done: false, value: 'foo' }
        console.log(generatorObject.next('bar')); // { done: true, value: 'bar' }

  4、 yield* 委托给其他生成器或者可迭代对象

  (1)yield* 委托给其他可迭代对象

  可以使用星号增强 yield 的行为,让它能够迭代一个可迭代对象,从而一次产出一个值,因为 yield * 实际上只是将一个可迭代对象序列化为一连串可以单独产出的值,所以这跟把 yield 放到一个循环里没什么不同。下面两个生成器函数的行为是等价的:

        function* generatorFnA() {
            for (const x of [1, 2, 3]) {
                yield x;
            }
        }
        console.log(generatorFnA());
        for (const x of generatorFnA()) {
            console.log(x);
        }
        // 1
        // 2
        // 3
        function* generatorFnB() {
            yield* [1, 2, 3];
        }
        for (const x of generatorFnB()) {
            console.log(x);
        }
        // 1
        // 2
        // 3

  (2)yield* 委托给其他生成器

        function* createNumberIterator() {
            yield 1;
            yield 2;
            return 3;
        }
        function* createRepeatingIterator(count) {
            for (let i = 0; i < count; i++) {
                yield "repeat";
            }
        }
        function* createCombinedIterator() {
            let result = yield* createNumberIterator();
            yield result;
            yield* createRepeatingIterator(result);
        }

        var iterator = createCombinedIterator();
        console.log(iterator.next()); // "{ value: 1, done: false }"
        console.log(iterator.next()); // "{ value: 2, done: false }"
        console.log(iterator.next()); // "{ value: 3, done: false }"
        console.log(iterator.next()); // "{ value: "repeat", done: false }"
        console.log(iterator.next()); // "{ value: "repeat", done: false }"
        console.log(iterator.next()); // "{ value: "repeat", done: false }"
        console.log(iterator.next()); // "{ value: undefined, done: true }"

  上面的代码中createCombinedIterator()生成器委托了 createNumberIterator 生成器,并将它的返回值赋值给了result变量,yeild result 输入该变量值3,result变量接下来作为参数传递 createRepeatingIterator()生成器,提示同一字符串需要调用3次。

写在最后

  以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。

 

 

posted @ 2021-12-10 13:57  zaisy'Blog  阅读(198)  评论(0编辑  收藏  举报