• 32.JavaScript类数组(Array-like)和可迭代对象(Iterable-object)的实现原理



    在这里插入图片描述


    文章目录

    可迭代对象(Iterable object)

    数组是一个特殊的对象,它和普通对象的区别不仅仅在于元素的顺序访问、存储。另外一个重要的区别是:数组是可迭代的,也就是可以使用for ... of语句访问(迭代)所有的元素。

    我们可以简单的做一个小实验:

    let arr = [1,2,3,4,5]
    for(let val of arr){
        console.log(val)
    }
    
    • 1
    • 2
    • 3
    • 4

    代码执行结果:

    image-20220604080921048

    以上代码就简单的使用了数组的迭代特性,我们在访问数组元素的时候,不必使用元素的下标。

    如果我们对一个普通对象使用for ... of语句会发生什么呢?

    let obj = {
        name:'xiaoming',
        age:12,
    }
    for(let para of obj){ //代码会报错
        console.log(para)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    执行效果如下:

    image-20220604081556714

    这就证明普通的对象和数组之间还有一个可迭代的差距,我们称具备迭代功能的对象为可迭代对象

    Symbol.iterator

    如果我们希望一个对象可以迭代,必须为对象添加一个名为Symbol.iterator的方法(一个专门使对象可迭代的内建Symbol)。

    方法作用包括:

    1. 当使用for ... of循环迭代对象时,就会调用Symbol.iterator方法,这个方法必须返回一个迭代器(一个有next()方法的对象)。
    2. 得到迭代器后,for ... of会不断的调用迭代器的next()方法获得下一个元素。
    3. next()方法返回的内容必须符合格式:{done:Boolean,value:any},当done:true时,循环结束,否则value就是下一个值。

    迭代器:

    迭代器是借鉴C++等语言的概念,迭代器的原理就像指针一样,它指向数据集合中的某个元素,你可以获取它指向的元素,也可以移动它以获取其它元素。迭代器类似于数组中下标的拓展,各种数据结构,如链表(List)、集合(Set)、映射(Map)都有与之对应的迭代器。

    JS中的迭代器是专门为了遍历这一操作设计的。每次获取到的迭代器总是初始指向第一个元素,并且迭代器只有next()一种行为,直到获取到数据集的最后一个元素。我们无法灵活移动迭代器的位置,所以,迭代器的任务,是按某种次序遍历数据集中的元素

    作者:czpcalm
    链接:https://juejin.cn/post/6873457657018728456
    来源:稀土掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    实现一个可迭代对象:

    let obj = {
        from:1,
        to:5,
    }
    obj[Symbol.iterator] = function(){
        //返回一个迭代器
        return {
            current:this.from,
            last:this.to,
            next(){
                if(this.current
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    代码执行效果:

    image-20220604083540285

    注意,以上对象虽然可以进行迭代了,但是,迭代使用使用的材料并非对象,而是Symbol.iterator返回的迭代器(也是一个对象)。

    把对象本身构造成迭代器

    以上代码构造了一个内建函数Symbol.iterator(),这个函数返回了一个迭代器对象。我们还可以采用另外一种实现迭代器的方式:把对象本身做成迭代器:

    let obj = {
        from:1,
        to:5,
        [Symbol.iterator](){
            this.current = this.from;
            return this;//返回对象本身
        },
        next(){//给对象添加一个next方法
            if(this.current
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    代码执行效果和上面的图片展示相同。

    这么做虽然代码更加简洁了,但是由于并没有新的可迭代对象产生,我们就没有办法同时执行两个for ... of循环迭代同一个对象了,但是两个并行的迭代在同一个对象上是非常罕见的。

    我们可以总结可迭代对象的概念:

    所谓可迭代对象,就是比普通对象多了一个名为Symbol.iterator方法的普通对象,这个方法返回一个迭代器。

    或者,一个具备Symbol.iterator同时具备next方法的对象也是一个可迭代的对象。

    String也是可迭代的

    数组和字符串都是可以迭代的,我们可以很方便的使用for...of语句迭代数组中的字符元素:

    let str = '123'
    for(let c of str){
        console.log(c)
    }
    
    • 1
    • 2
    • 3
    • 4

    这对于代理对(UTF-16扩展字符)同样是有效的:

    let str = '?????????????????????'
    for(let c of str){
        console.log(c)
    }
    
    • 1
    • 2
    • 3
    • 4

    执行效果如下:

    image-20220604085545804

    String的迭代器

    并非只有for...of语句能够使用迭代器,我们还可以显式的调用迭代器:

    let str = '12345'
    let itr = str[Symbol.iterator]()
    while(true){
        let result = itr.next()
        if(result.done)break;
        console.log(result.value)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码执行效果:

    image-20220604085813686

    以上代码执行了遍历字符串字符的操作,是不是觉得可迭代对象就没有这么神秘了!

    类数组对象和可迭代对象

    类数组和可迭代在遍历功能上非常相似,都可以方便的方式内部元素,但是二者仍然有明显的区别:

    1. iterable可迭代对象:实现了Symbol.iterator的对象;
    2. array-like类数组对象:具有数字索引,并且有length属性;

    字符串就是一个即使类数组又是可迭代的对象。

    可迭代和类数组对象通常都不是数组,如果我们想把一个可迭代或者类数组对象转为数组,需要使用Array.from方法。

    Array.from

    使用Array.from将字符串转为数组:

    let str = '123'
    let arr = Array.from(str)
    console.log(arr)
    
    • 1
    • 2
    • 3

    代码执行效果如下:

    image-20220604091552590

    把自定义的类数组对象转为数组:

    let obj = {
        0:'0',
        1:'1',
        2:'2',
        length:3
    }
    let arr = Array.from(obj)
    console.log(arr)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代码执行结果:

    image-20220604091736400

    Array.from的完整语法:

    Array.from(obj[, mapFunc, thisArg])
    
    • 1

    mapFunc方法会在生成数组之前对每个可迭代或类数组元素调用,如果mapFunc是一个成员方法,可以使用thisArg提供this指针。

    举个例子:

    let str = '12345'
    let arr = Array.from(str,itm=>+itm)
    console.log(arr)
    
    • 1
    • 2
    • 3

    代码执行结果:

    image-20220604092137378

    这里通过映射函数,将本应该生成字符数组转为数字数组。

    总结

    1. 可以使用for...of语法的对象被称为可迭代对象
    2. 可迭代对象是在普通对象的基础上实现了Symbol.iterator方法的对象
    3. Symbol.iterator方法返回了一个迭代器;
    4. 迭代器包含一个next方法,该方法返回下一个元素的值;
    5. next方法返回值需要满足格式{done:Boolean,value:nextVal},当done:true时,迭代结束
    6. Array.from可以把类数组和可迭代对象转为数组;

    在这里插入图片描述

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    Fabric.js 图案笔刷
    【HDU No. 2586】 树上距离 How far away ?
    [Unity]对接华为sdk 登录
    Git 的内部工作原理
    互联网、政务外网、政务专网、政务内网的区别
    普通大学生的真实出路
    高NA镜头系统中的高级PSF计算
    [SDR] GNU Radio 系列教程(十四) —— GNU Radio 低阶到高阶用法的分水岭 ZMQ 的使用详解
    linux系统gitlab的安装与使用
    Navicat Premium 16 安装及卸载
  • 原文地址:https://blog.csdn.net/hjseo_seg/article/details/126097736