【JS基础】前端如何优雅的处理类数组对象?

前端如何优雅的处理类数组对象?

一、背景介绍

Leo 部门最近来了位前端实习生 Robin,作为师傅,Leo 认真的为 Robin 介绍了公司业务、部门工作等情况,还有前端的新人学习地图。

接下来 Robin 开始一周愉快的学习啦~

一周后,Leo 为 Robin 同学布置了学习作业,开发一个【人员搜索选择】的页面,效果大致如下:

在这里插入图片描述
Robin 看完这个效果图后,一脸得意的样子,这确实不难呀~

过几天后,Robin 带着自己写的代码,给 Leo 展示了她的代码,并疑惑的问到:

在这里插入图片描述
她将这个“数组”输出到控制台:

在这里插入图片描述
Leo 看了看代码:

getUserList(){
   const memberList = $('#MemberList li');
   memberList.map(item => { console.log(item) });
   console.log(memberList);
}

Leo 又问到:

在这里插入图片描述
Robin 一脸疑惑,然后 Leo 再原来代码上,加了个 Array.from 方法如下:

getUserList(){
    const memberList = Array.from($('#MemberList li'));
    memberList.map(item => {
        console.log(item)
    })
    console.log(memberList)
}

然后重新执行代码,输出下面结果:
在这里插入图片描述
Leo 输出的结果,跟 Robin 说到:

在这里插入图片描述
Robin 满脸期待望着师傅,对类数组对象更加充满期待。

二、类数组对象介绍
2.1 概念介绍

所谓 类型化数组对象(简称类数组对象) 是一种类似数组的对象,它提供了一种用于访问原始二进制数据的机制。JavaScript引擎会做一些内部优化,以便对数组的操作可以很快。然而,随着Web应用程序变得越来越强大,尤其一些新增加的功能例如:音频视频编辑,访问WebSockets的原始数据等,很明显有些时候如果使用JavaScript代码可以快速方便地通过类型化数组来操作原始的二进制数据将会非常有帮助。—— 《MDN 类型化数组》

那么什么样的数组我们可以归类到类型化数组中?其实比较简单,和数组结构类似,拥有length属性,可以通过索引来访问或设置里面的元素,但是不能使用数组的方法,就可以归类为类型化数组。举个例子🌰:

const arrLike = {
  0: 'name',
  1: 'age',
  2: 'job',
  length: 3
}
2.2 常见类数组对象
  • arguments 对象;
function f() {
  return arguments;
}
f(1,2,3)

// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]

-NodeList(比如 document.getElementsByClassName('a') 得到的结果;

document.getElementsByTagName('img')
// HTMLCollection(3) [img, img, img]
  • typedArray(比如Int32Array`);
const typedArray = new Uint8Array([1, 2, 3, 4])
// Uint8Array(4) [1, 2, 3, 4]

另外使用 jQuery 获取元素,会被 jQuery 做特殊处理成为 init 类型:

$('img')
// init(3) [img, img, img, prevObject: init(1), context: document, selector: "img"]
三、类数组对象属性

下面通过 Robin 代码作为示例,介绍类数组对象的属性:

const memberList = $('#MemberList li');
3.1 读写
// 读取
memberList[0];
// Node: <li>...</li>

// 写入
memberList[0] = document.createElement("div")
memberList[0];
//  Node: <div>...</div>
3.2 长度
memberList.length; 
// 10
3.3 遍历
for (let i = 0;i < memberList.length; i++){
    console.log(memberList[i]);
}

/*
 Node: <li>...</li>
 Node: <li>...</li>
  ... 共10个,省略其他
*/

memberList.map(item => console.log(item));

/*
 0
  ... 共10个,省略其他
*/

但如果是HTMLCollection就不能使用 map 咯:

const img = document.getElementsByTagName("img");
img.map(item => console.log(item));

// Uncaught TypeError: img.map is not a function
四、类数组对象处理

Leo 看了看 Robin 处理这个列表的代码:


getUserList(){
    const memberList = $('#MemberList li');
    const result = {
        text: [],
        dom : [],
    };
    memberList.map(item => {
        item = memberList[item]
        // 判断当前节点是否有 checked 类名
    })
    console.log(result)
    this.showToast(`选中成员:${result.text}`);
}

很明显,Robin 并没有对 jQuery 获取到的 memberList做处理,直接使用,通过索引来获取对应值。Leo 继续和 Robin 介绍到:
在这里插入图片描述

4.1 Array.from

使用Array.from来将类数组对象转为数组对象,操作起来非常简单:

getUserList(){
    const memberList = Array.from($('#MemberList li'));
    // 省略其他代码
}

语法如下:

Array.from(arrayLike[, mapFn[, thisArg]])

参数:

  1. arrayLike想要转换成数组的伪数组对象或可迭代对象。
  2. mapFn 可选如果指定了该参数,新数组中的每个元素会执行该回调函数。
    3.thisArg可选可选参数,执行回调函数mapFnthis对象。

返回值:一个新的数组实例。

更多Array.from 介绍可以查看文档。

4.2 Array.prototype.slice.call()

slice()方法返回一个新的数组对象,这一对象是一个由beginend决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变

实现代码:

getUserList(){
    const memberList = Array.prototype.slice.call($('#MemberList li'));
    // 省略其他代码
}

更多 Array.prototype.slice 介绍可以查看文档。

4.3 ES6展开运算符

展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。

实现代码:

getUserList(){
    const memberList = [...document.getElementsByTagName("li")];
    // 省略其他代码
}

更多 ES6展开运算符 介绍可以查看文档。

4.4 利用concat+apply

getUserList(){
    const memberList = Array.prototype.concat.apply([], $('#MemberList li'));
    // 省略其他代码
}
五、案例小结

Leo 介绍完这些知识后,Robin 又优化了下自己的代码,涉及到类数组对象操作的核心 js 代码如下:

class SelectMember {
    constructor(){
        this.MockUsers = window.MockUsers;
        this.init();
    }
    init(){
        this.initMemberList('#MemberList', this.MockUsers);
        this.initBindEvent();
    }
   // ... 省略部分代码,保留核心代码
    submitSelect(){
        const memberList = Array.from($('#MemberList li'));
        const result = {
            text: [],
            dom : [],
        };
        memberList.map(item => {
            const hasClass = $(item).children('.round-checkbox').children('span').hasClass(this.selectClassName);
            if(hasClass){
                result.text.push($(item).children('.user-data').children('h4').text());
                result.dom.push(item);
            }
        })
        this.showToast(`选中成员:${result.text}`);
    }
}

let newMember = new SelectMember();

很明显,使用正确方式来处理类数组对象,不仅能使我们代码更加少,减少转换处理,还能提高代码质量。

六、总结

本文我们通过一个实际场景,详细介绍了类数组对象在实际开发中的使用,对于常见的类数组对象,我们还介绍了处理方式,能很大程度减少我们处理类数组对象的操作,将类数组统一转成数组,更加方便对数据的操作。希望看完本文的你,以后再遇到类数组对象,不会再一脸懵逼咯~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值