迭迭迭代器?

一、什么是迭代器

说起迭代,小伙伴们肯定很熟悉!!我们可能经常听到这样一句话“xxx是可迭代的”,在疑惑的同时,我们心里肯定也在想,逼格这么高的词汇,我要是可以用到,那岂不是佬中佬?emmm…其实也没有那么高逼格,让我们一步步揭开它的面纱~
要知道,你好像在学一个很新的东西,所以看官方文档肯定是最靠谱不过的了。对于迭代器,mdn上是这样解释的:
“在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。更具体地说,迭代器是通过使用 next() 方法实现 Iterator protocol 的任何一个对象,该方法返回具有两个属性的对象: value,这是序列中的 next 值;和 done ,如果已经迭代到序列中的最后一个值,则它为 true 。如果 value 和 done 一起存在,则它是迭代器的返回值。”
我们可以看到:
1.迭代器是一个对象
2.迭代器里面必须要有一个next方法,通过next方法实现迭代
3.next方法必须返回一个对象
即迭代器是一个对象,这个对象一定要有next方法去实现迭代(要符合Iterator协议,不然不能够被叫做迭代器),同时next也要返回一个对象(要符合Iterator协议),这样是不是更加清楚一点了?还有更清楚的,就是我个人理解(TAT)
迭代器是一个对象(其实就是对象。。。。逼格一下子就下去了),使用户在容器(数组,链表等)对象上遍历的对象,迭代的时候不需要关心容器对象的内部实现细节(管你内部的结构是咋样,该迭还得迭)
即:
帮我们对某个数据结构进行遍历的对象
在js里面迭代器必须符合迭代器协议
next也有自己的要求:
有一个无参数或者一个参数的函数,返回一个对象:
{
done:布尔值,迭代对象是否迭代完,迭代之后为true
value:具体值(要有值~)/undefined
}
实践是检验真理的唯一标准,所以,手写一个迭代器,如何?

  const nums = [1, 2, 3, 4, 5] //实现针对数组的自定义迭代器,虽然数组自带迭代器(一个对象而已)
        function createIterator(arr) { //返回一个迭代器,要按自定义的规则迭代,不管你是什么数组,
            let i = 0;
            return {
                // 因为还在使用i值,所以这个函数不会被回收
                next: function () { //适合数组的迭代器
                    if (i < arr.length) {
                        return { //next要返回一个对象
                            done: false,
                            value: arr[i++]
                        }
                    } else {
                        return {
                            done: true,
                        }
                    }
                }
            }
        }
        const iterator = createIterator(nums) //返回一个迭代器(就是一个对象啦)
        console.log(iterator) //真的是一个对象,官方诚不欺我
        console.log(iterator.next())//调用迭代的next方法对其进行迭代	
       /* {
       	返回值是这个,一直调用的话,会一直遍历,直到遍历完之后,返回{done:true}
   		 "done": false,
   		 "value": 1 
		}*/
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())
        //这样就实现了一个针对数组的自定义迭代器,其实就是:
        //迭代器(一个实现了符合Iterator协议的next方法的对象)

大家可能会疑惑,为什么明明调用完成了,i还可以继续用,因为next方法始终要用到createIterator的i值,所以这个函数的空间不会被释放,即i值一直存在

二、什么是可迭代对象

了解了什么是迭代器(一个实现了符合Iterator协议的next方法的对象)之后,我们又回到了上面的那个问题,“xxx是不可迭代的”,那,到底啥才是迭代对象呢,啥又是不可迭代的对象呢?
官方解释是:“要成为可迭代对象,该对象必须实现 @@iterator 方法,这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性”
我们又可以看到:对象里面或者它的原型上必须要有 @@iterator 方法
啊这这这,@@iterator方法好抽象啊,到底是啥啊
别急,官方还有解释:
“可通过常量 Symbol.iterator 访问该属性”,访问?那Symbol.iterator生成一个变量咯,那方法名就是介个样子:[Symbol.iterator](都说可以访问了,那么使用这个语法访问该属性)
那知道了,实现了@@iterator方法的对象(或者在原型上有)就可以被叫作可迭代对象,那原生里面到底有哪些是可迭代对象呢?我们平时经常用到的大概有这些:Array,Map,Set,String,TypedArray,arguments 等。是的,没有对象,那可迭代对象上面真的实现了@@iterator方法吗?那数组和对象来举例,打印出来对比一下~

 const arr = []
 console.log(arr)

结果打印
数组的原型链上有使用Symbol.iterator来访问@@iterator方法,根据mdn说法,这是一个可迭代对象!

再打印对象出来看看!

  const obj = {}
  console.log(obj,obj[Symbol.iteraor])

在这里插入图片描述

啊,对象或者对象的原型上没有实现@@iterator方法,根据标准对象是不可迭代的,那我们可能会想,每一次都要打印一次,那不是麻烦死了,其实我们可以使用for…of…来检测:
先检测对象

 const obj = {
            name:"aaa",
            age:"bbb"
        }
        for(let item of obj){
            console.log(item)
        }

在这里插入图片描述
报错:obj不是可迭代的

再看看数组:

const name =["aaa","bbb"]
        for(let item of name){
            console.log(item)
        }

在这里插入图片描述
好神奇!

其实用for of 来检测一个对象是不是可迭代的并不是,空穴来风,mdn上也有提到:
“for…of 语句遍历可迭代对象定义要迭代的数据。”
所以以后如果相检测一个东西是不是可迭代的,最简单的方法使用for of

三、让一个对象成为可迭代的

上面已经提到,对象是不可迭代的,但是我们有办法让它变成迭代的,怎么来呢~肯定是符合官方的定义:在对象或者其原型上有一个[Symbol.iterator]方法!仅仅有这一个方法就够了嘛?肯定不是:
“如果一个可迭代对象的 @@iterator 方法不能返回迭代器对象,那么可以认为它是一个不符合标准的(Non-well-formed)可迭代对象。”
-----mdn官方文档
所以这个方法必须返回一个迭代器对象,让我们回想一下迭代器对象~~
迭代器对象:一个实现了符合Iterator协议的next方法的对象
哦,现在我懂了,开始写代码叭

        class Person {
            // 这个类的实例都可以变成可迭代对象
            constructor(name, age) {
                this.name = name
                this.age = age

            }
            [Symbol.iterator]() {
                // 将这个放在Person的显示原型上,这样所有的类实例都可以访问
                let index = 0
                const keys = Object.keys(this) //实例方法调用
                const Iterator = {
                    next: function () {
                        if (index < keys.length) {
                            return {
                                value: keys[index++],
                                done: false
                            }
                        } else {
                            return {
                                done: true
                            }
                        }

                    },
                    return: () => {
                        return {
                            done: true //当迭代器中端的时候会调用这个方法进行处理或者提示
                        }
                    }
                }
                return Iterator
            }
        }
        const p1 = new Person("wx", 21)
        for (let item of p1) {
            console.log(item)
        }

打印出来看看~
在这里插入图片描述
可以看到不报错了~因为上面是对对象的key进行迭代,如果需要对其value进行迭代的话,可以改


四、总结

经过上述,可能大家对于迭代器已经有一个初步的了解了:
1.其实迭代器就是一个普普通通的对象,但是它符合了迭代协议,所以才被叫做迭代器,进一步说,一个普普通通的对象都可以成为迭代器,只要它符合迭代协议。
2.并不是所有的对象都是可迭代的,只有实现了[Symbpl.iterator]方法,并且这个方法也要返回一个迭代器,才可以进行迭代的
3.可以使用for of 来检测一个对象是不是可迭代对象
4.本文还有很多没有说到的地方,比如迭代器里面除了必须的next方法有详细说到以外,其他的return方法,throw方法等都没有说到,感兴趣的小伙伴们可以去mdn上官网查阅~
5.迭代器也有异步的,本文只说明了同步的
6.只有学好了迭代器才可以明白生成器的作用和实际内容,所以下一节内容是:生成器!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值