es6--生成器

本文深入探讨了生成器在ES6中的迭代器特性,通过实例和协议解释了为何生成器对象是迭代器。通过gen()函数和yield语句的实例,展示了生成器如何实现迭代协议,以及如何在控制台上验证其原型链关系。最后,文章总结了生成器的关键特征和工作原理。
摘要由CSDN通过智能技术生成

生成器

  • 关于为什么生成器对象就是迭代器问题的探索
  • 对于生成器的举例解析

关于为什么生成器对象就是迭代器问题的探索

对于es6里面的生成器,最开始是看视频了解的,并不是特别深刻,只是知道生成器对象是迭代器。前几天复习的时候忽然在想生成器对象为什么可迭代,生成器对象是迭代器又从何而知呢?
查阅了一些关于迭代的东西(迭代协议),里面这么定义到。

作为 ECMAScript 2015 的一组补充规范,迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。
迭代协议具体分为两个协议:可迭代协议和迭代器协议。

可迭代协议里提到

要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性

迭代器协议中也提到

只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才能成为迭代器

文本的理解可能不够生动,我们来举个例子说明这个问题。

 function * gen(){
            console.log(111);
            yield '一只没有耳朵';
            console.log(222);
            yield '一只没有尾部';
            console.log(333);
            yield '真奇怪';
            console.log(444);
        }
        let iterator = gen();
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());
        console.log(iterator.next());

上述例子中,按照生成器对象就是迭代器这句话反推的话,那么 gen() 就是迭代器 gen就是生成器函数。
那么在控制台去找,我们找到了生成器对象原型链的原型,以及迭代器原型链的原型链(如图所示)。
生成器原型链的原型:
在这里插入图片描述

迭代器原型链的原型链:
在这里插入图片描述
再在控制台输入下面这段代码:

gen.__proto__.prototype == gen().__proto__.__proto__

输出结果如下:
在这里插入图片描述
这样就可以得到生成器对象原型链的原型=迭代器原型链的原型链。
(ps:上述代码运行结果演示):
在这里插入图片描述
后面有看到书上说

执行Generator函数会返回一个遍历器对象。

所以上面的探索也可以用这个解释,不需要这么麻烦的思考过程(但是感觉会印象深刻一些)。

对于生成器的举例解析

Generator函数是一个普通的函数,但又两个特征:

  1. function命令与函数名之间有一个星号(*)
  2. 函数体内部使用yield 语句定义不同的内部状态。

还是用例子来说明这个东西更加形象一些。

 function * gen(arg){
            console.log(arg);
            let one = yield 111;
            console.log(one);
            let two = yield 222;
            console.log(two);
            let three = yield 333;
            console.log(three);
        }
        let iterator = gen('AAA');
        console.log(iterator.next());
        console.log(iterator.next('BBB'));
        console.log(iterator.next('CCC'));
        console.log(iterator.next('DDD'));

运行结果一并给出在来看这段代码的分析:
在这里插入图片描述

  • 开始先传入AAA ,但这个时候只是传参,并没有执行。
  • 上面说到生成器对象就是迭代器。所以下面的console.log(iterator.next())运行的部分就是上面函数从开始到第一个yield这部分,但是不进行上面let one 的赋值,返回111。function中打印出arg 也就是AAA,下面console.log(iterator.next())打印出的是object{value:111,done:false}。
  • console.log(iterator.next('BBB'))这段传入的是BBB,执行的是上面函数第一个yield到第二个yield,给let one进行赋值操作,但不给let two进行赋值操作,并返回222。所以上面函数中打印one结果出来是BBB,下面console.log(iterator.next(‘BBB’))打印的是object{value:222,done:false}。
  • 下面基本都是这种类型,但是最后,three打印的是DDD,但这是没有yield,也进行到了函数的结尾,这个时候返回的object则为object{value:undefined,done:true}。这里面的true表示迭代结束。
    那么如果了解了上面这个例子,那我们把他进行变形再来看看
function * gen(arg){
            console.log(arg);
            let one = yield 111;
            console.log(one);
            console.log(yield 111);
            console.log(one);
            let two = yield 222;
            console.log(two);
            let three = yield 333;
            console.log(three);
        }

        //执行获取迭代器对象
        let iterator = gen('AAA');
        console.log(iterator.next());
        console.log(iterator.next('BBB'));
        console.log(iterator.next('CCC'));
        console.log(iterator.next('DDD'));

这个例子中仅仅多了两行,但是理解确实有一定难度。
提醒一下,yield是一个关键字不能放在console.log中,否则会产生一定影响。
开始的时候额米有注意,但是后面看了一会发现用这个例子却更好理解一些。

  • 第一步和上面的是一样的。
  • 第二步中,传BBB时,这时候是从第一个yield 111console.log(yield 111)。这个时候是给 let one 赋值了,所以会出现BBB,但是内个console.log(yield 111)是到这里截止,不会打印,但是返回了111,下面的console.log(iterator.next('BBB'))会打印出object{value:111,done:false}。
  • 第三步传CCC时,从第二个yield到第三个yield,这里打印了console.log(yield 111),注意这个时候yield接收的是CCC,所以会打印CCC。这个后面打印了一次one,也就是BBB,返回了222,所以紧跟着打印的是object{value:222,done:false}。
  • 这里可以发现出现了错位,所以到最后并没有打印出object{value:undefined,done:true}。
    运行结果如下:
    在这里插入图片描述
    这里可以给最后一行加上
        console.log(iterator.next('eee'));

这个时候就可以补上,并出现object{value:undefined,done:true}
多出来的运行结果如下:
在这里插入图片描述
关于上述两个问题,到这里我的理解就结束了,谢谢观看。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值