迭代器(iterator)和 生成器(generator)

迭代器(iterator)

什么是iterator?

迭代器(iterator)是一种统一的接口机制,它是一种接口,为不同的数据结构提供统一的访问机制,任何数据只要定义了iterator接口,就可以完成遍历操作。

模拟一个迭代器

在js里,一个对象中含有next()方法,并且这个next()方法返回一个对象那么这个对象就是一个迭代器,每一次调用next()方法都会返回一个包含value和done两个属性的对象,value表示数据集合当前成员的值,done是一个布尔值,表示遍历是否结束。

let arr = [1, 2, 3, 4,5];
//模拟的迭代器,使用这个迭代器遍历上面的数组
const iterator = {
            // 索引,for循环遍历里的i的作用
            i : 0,
            next() {
               return {
                    value : arr[this.i],
                    // 设置迭代状态 (后面还有没有数据)
                    //done为true则数组里已经没有数据结束
                    //false则还有数据 
                    //i++索引自增
                    done : this.i++ >= arr.length 
                }
            }
}
//来试用一下这个迭代器
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

效果:
在这里插入图片描述
如果要取值的话打点使用value就可以了

原生的迭代器

for-of

这里要介绍一下es6的一个新遍历方法: for-of
用法和 for-in几乎一样,但是for-of无法遍历 没有iterator的数据
比如对象,数据的‘集合’Object是可以使用for-in遍历的,但是他不能使用for-of

        var obj = {
            name : "jack", 
            age : "13",
            gender : "男"
        }
        for(const item of obj) {
            console.log(item);
        }

最后的结果报错: TypeError: obj is not iterable
类型错误:obj不是可以迭代的

为什么要先介绍for-of呢?

Symbol.iterator迭代器接口

在ES6中,有些数据结构原生具备Iterator接口(比如数组)。可以被for-of遍历,但是对象就不行,原因在于,数组原生定义了Symbol.iterator属性,Symbol.iterator被称为迭代器接口,调用这个接口就可以返回一个迭代器对象

        var arr = [1, 2, 3, 4];
        let iter = arr[Symbol.iterator]();
        console.log(iter.next());
        console.log(iter.next());
        console.log(iter.next());
        console.log(iter.next());
        console.log(iter.next());

在这里插入图片描述
可以看到打印出来的对象和我们上面的自定义的迭代器返回的东西是一样的。

类数组对象也可以迭代

如果了解过解构赋值的话,就知道字符串是可以进行解构赋值的,而原理就是讲字符串转换为类数组,而类数组中是带有Symbol.iterator属性的。

        function test(a,b,c){
           console.log(arguments[Symbol.iterator]().next());
        }
        test(1,2,3);

在这里插入图片描述

让一个对象可以迭代

说了那么多,我们来试一试给对象设置一个迭代器接口

       var obj = {
            a: '你好',
            b: "我好",
            c: "大家好",
            [Symbol.iterator]() {
                // 获取key属性名
                let key = Object.keys(this);
                // 设置索引
                let i = 0;
                return {
                //防止this指想出现问题,所以使用了箭头函数
                    next: () => {
                        return {
                            value: {
                                key: key[i],
                                val: this[key[i]]
                            }
                        }
                    }
                }
            }
        }
        //这次我们再去调用for-in方法
        for (const item of obj) {
            console.log(item);
        }

在这里插入图片描述
成功地给对象添加了迭代器接口 !
在这里插入图片描述

说完迭代器 那么接下来说 生成器

生成器(generator)

有什么用?

生成器函数可以让一个函数分段执行。

使用方法

首先在function关键字和函数名之间添加一个 星号 如: function * fn()
想让函数分段执行的话,给函数中间添加yield关键字。

       function* test(){
            let num=0;
            num+=10;
            console.log(num);
            console.log("这是第一段代码");
            yield ;
            num+=10;
            console.log(num);
            console.log("这是第二段代码");
            yield ;
            num+=10;
            console.log(num);
            console.log("这是第三段代码");
            yield ;
            num+=10;
            return num;
        }
        var mytest=test();
        console.log(mytest);
        mytest.next();
        mytest.next();
        mytest.next();
      var ret=mytest.next();
      console.log("这是返回值:"+ret.value);

在这里插入图片描述
生成器函数分段执行,有以下几个点:

1.generator函数的写法跟普通函数有区别 在function关键字和函数名之前加一个*

通常情况下 *紧挨着function写

2. generator函数是分步执行的 以yield 为标志 表示函数暂停执行 通过调用next方法恢复函数执行

这就是迭代器的又一个用处

3.generator函数直接调用 是不会执行函数体的 而是要调用next方法 才能往下执行

生成器还是遵循原始函数的一些规则的,如果你 return的话 后面的代码就不会执行

4.generator函数调用之后 返回的值是一个iterator对象 只有调用next方法 才会迭代 进入下一个状态

5.Async和 * 不能同时使用

**async function * fn();** 不可以

next的传参问题

next是一个方法,那这个方法的参数是干什么的呢?

function* fn() {
            let num = yield 2;
            console.log(num);

            num = yield 1 + num;
            console.log(num);

            yield 3;

        }

        const ger = fn();
        console.log(ger.next(111));
        console.log(ger.next(111));
        console.log(ger.next(111));

在这里插入图片描述
每次都打印的是111

调用next方法 是可以传参的 传入的参数 会交给yield表达式的返回值

也就是说传入的参数会作为yield的返回值。

在一个生成器里调用另一个生成器

在生成器内部调用其他的生成器 一定要在yield 后面加上*

function* f1(){
            yield 1;
            yield 2;
            yield 3;
        }
        function* f2(){
            yield* f1();
            yield 4;
            yield 5;
            yield 6;
        }
        var res=f2();
        console.log(res.next())
        console.log(res.next())
        console.log(res.next())
        console.log(res.next())
        console.log(res.next())
        console.log(res.next())
        console.log(res.next())
        console.log(res.next())

在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值