一文搞懂前端的所有类数组类型

这篇具有很好参考价值的文章主要介绍了一文搞懂前端的所有类数组类型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前面博文有介绍JavaScript中数组的一些特性,通过对这些数组特性的深入梳理,能够加深我们对数组相关知识的理解,详见博文:
一文搞懂JavaScript数组的特性

其实,在前端开发中,除了数组以外,还有一种类似数组的对象,一般叫做类数组、或伪数组,也是我们需要掌握的知识点。

类数组是什么?

首先,我们先尝试给类数组加个简单的定义:拥有length属性的对象(非数组)。类数组的核心特征就是拥有length属性,拥有length属性又不是真正数组的对象,基本可以被认定为类数组。
虽然这个定义很简单,只突出了length属性,但类数组的基本特点,我们还是可以总结如下:

  • 拥有length属性
  • length属性非动态值,不会随元素变化而变化
  • 可以使用数字索引下标访问属性元素
  • 不是数组,没有数组对应的各种方法
  • 可以使用for语句等进行循环遍历
  • 能够通过一定方式转换成真正的数组

创建类数组的对象

根据以上类数组的特点,我们可以自己创建类数组的对象,也比较简单,只需要拥有length,如下所示:

const al = { 0: 111, 1: 222, 2: 333, length: 3 }
for (let i = 0; i < al.length; i++) {
  console.log(al[i])
}
// 111
// 222
// 333

以上代码,创建了一个length属性为3的对象,通过for循环遍历对象,并且下标输出对应的值。
length属性并不会动态添加,比如我们给al对象增加一个属性,但length值仍为3:

al[3] = 444
console.log(al.length) // 3

如果把该类数组对象转换成一个真正的数组后,就可以进行数组操作了。

事实上,我们可以省略其他属性,只保留length,同样可当做一个类数组使用:

const al = { length: 3 }

虽然我们可以通过类似这种方式,自己创建类数组,但实际开发过程中,几乎没人这么处理。
真正在前端开发中,接触到的类数组,都是JavaScript语言或者Web环境下提供的各种类数组的对象。
在介绍这些类数组对象之前,我们先看下类数组对象如何才能转换成数组。

如何将类数组转换成数组

类数组只是类似数组的对象,缺少很多相应的方法,有时候我们可能需要把类数组转换成数组,才能更好的操作,这时候就需要找到方便有效的转换方式。
当前常用的转换方式,大致有如下几类,我们一个个介绍。

Array.from()

首先是ES6提供的新的数组静态方法:Array.from,它用于从一个类数组或可迭代对象中创建一个新的数组。基本上,只要拥有length属性的对象,都能被Array.from转换成数组。
语法:Array.from(arrayLike, mapFn, thisArg)
三个参数说明:

  • arrayLike:类数组对象,或可迭代对象
  • mapFn:可选参数,新数组会经过该函数处理后返回
  • thisArg:可选参数,执行mapFn时指定的this指向

下面看一个示例:

const al = { 0: 111, 1: 222, 2: 333, length: 3 }
const arr = Array.from(al)
console.log(arr) // [111, 222, 333]
console.log(arr.length) // 3
console.log(Array.isArray(arr)) // true

以上代码,我们自定义了一个拥有length属性的对象,然后通过Array.from方法进行转换,得到了一个长度为3的新数组。
这种方式简单方便,在当前前端开发的绝大多数情况下,都应该是首选。

Array.prototype.slice.call()

在ES6没出来之前,如果想较好的进行类数组的转换,一般使用的是该方法:Array.prototype.slice.call()。
它基于数组的slice()方法,把执行时的this指向类数组对象,让类数组对象像数组一样使用slice()方法返回一个新的数组,因此拥有length属性的类数组对象都能被转换成数组。

const al = { 0: 111, 1: 222, 2: 333, length: 3 }
const arr = Array.prototype.slice.call(al)
console.log(arr) // [111, 222, 333]

以上代码,与Array.from定义同样的类数组对象,通过Array.prototype.slice.call转换,效果是一样的。

其他方式

以上两种方式,是最正确有效的转换,推荐日常使用。
除此以外,还有其他的方式,但各有缺陷,要么较复杂、要么对部分类数组对象不适用,所以并不太推荐。

  • for循环处理
    定义一个新的空数组,通过循环遍历类数组对象的属性,将类数组对象的每一个属性元素值都添加到新数组中。
    这种方式就显得相对麻烦一些。
  • 扩展运算符(...)
    扩展运算符主要作用于可迭代对象,JavaScript中的集合(数组、Set、Map)都是可迭代对象,另外字符串和arguments也都是。
    扩展运算符对于不可迭代对象,会报错。
[...'hello'] // ['h', 'e', 'l', 'l', 'o']
[...{ length: 3 }] // Uncaught TypeError: {(intermediate value)} is not iterable
Array.from({ length: 3 }) // [undefined, undefined, undefined]

以上代码,通过扩展运算符,字符串能被转换成数组,但自定义类数组对象 { length: 3 } 则不行,并报错;而使用Array.from则转成了拥有3个 undefined 元素的数组。

类数组对象

前端开发中最常见且被认可的类数组对象,是函数的arguments参数对象,另外字符串也是一个类数组对象,其他的还有各种Web环境提供的API。
如果把这些分成两类的话:

  • JS对象
    属于JavaScript语言的对象,在nodejs中也存在。
    如arguments、字符串、TypeArray、自定义类数组等。
  • Web对象
    依赖于Web环境(一般是浏览器)的对象,不属于JavaScript语言。
    如FileList、DOM列表对象、数据存储(如localStorage、sessionStorage)等。

下面我们就一一介绍下这些类数组对象。

JavaScript类数组对象

arguments

arguments是JS中函数内部的一个对象,用于处理不定数目的参数,是一个类数组对象。
在ES6推出之前,arguments的使用还是非常广泛的,但在ES6推出默认参数和扩展参数后,它的使用就减少了。

通过下面的示例,转成数组:

function test () {
  console.log(Array.prototype.toString.call(arguments))
  console.log(Array.from(arguments))
  console.log([...arguments], Array.prototype.slice.call(arguments))
}
test(23)
// [object Arguments]
// [23]
// [23] [23]

以上代码可知,该对象存在独特的类型判断 Arguments,可用扩展运算符处理arguments对象。

注意,箭头函数内部不存在arguments对象。

字符串

JavaScript中的字符串也是一个类数组对象,它拥有length属性,可以通过下标数字索引访问,也可以转换成数组,字符串中的每一个字符都变成新数组的一个元素。

const str = 'abc'
str.length // 3
str[1] // 'b'
Array.from(str) // ['a', 'b', 'c']
[...str] // ['a', 'b', 'c']

字符串拥有一个实例方法 split,可以将字符串按照传入的分隔符进行处理,返回一个分割出来的每个子字符串都作为元素的数组:

'abc'.split('') // ['a', 'b', 'c']
'abc'.split('b') // ['a', 'c']

以上代码,
当使用空字符做分隔符的时候,就是将每一个字符都分割成数组元素,与类数组的转换方式相同。
当使用 b 字符做分隔符的时候,返回的数组元素就只有2个了。

由于split操作分隔符的灵活性,可以给我们处理字符串带来方便,所以常用该方法,而少用类数组转换。

TypeArray类型数组

类型数组也是一种类数组对象,提供了访问内存缓冲区中二进制数据的机制,它拥有11个对象,如Uint8Array、Uint8ClampedArray、Int32Array、Float64Array等等。具体知识可见博文前端二进制API知识总结

类型数组都拥有和数组相同的大部分用于遍历的实例方法,但它不是真正的数组,它不能动态变化,不支持push、pop、shift、unshift等修改数组的方法,类型判断也不是数组:

const u8 = new Uint8Array()
u8 instanceof Uint8Array // true
Array.isArray(u8) // false
[...u8] // []
Array.from(u8) // []

以上代码,可以看出,类型数组并不是真正的数组,但可以通过扩展运算符转换成数组(其他方式也行)。
当然,类型数组的使用场景一般在于处理二进制数据,能够遍历读取数据做一些操作即可,并不太需要做转换。

其他JS类数组对象

  • 自定义类数组对象
    前面已有介绍,开发中几乎不用。

  • function
    函数作为一个对象,也拥有length属性,所以它也可以转换成数组。
    函数的length属性表示的是参数的个数,转成数组后,就表示有几个元素,但元素值都为undefined。

    const fun = (al) => {}
    fun.length // 1
    Array.from(fun) // [undefined]
    

Web-API类数组对象

FileList

FileList对象是一个我们常常用到的类数组对象,主要是在文件上传的过程中,我们选择文件后,前端用于接收文件信息的对象,就是它,可以读取到单个或多个文件数据。

FileList是一个拥有length属性并且属性索引值是数字的对象,它的每一个子成员属性都是一个 File 对象,处理文件信息。

inputFile.addEventListener('change', (e) => {
  const files = e.target.files
  console.log(Array.from(files))
})
// [File]

以上代码,就是监听一个上传控件的change事件,读取到对应的文件列表,并转换输出为数组,元素为File对象。

一般也用不着转换,直接遍历读取FileList即可。

DOM中类数组

在Web开发中,DOM操作也有很多类数组对象,如元素集合HTMLCollection、节点NodeList等等。

HTMLCollection

HTMLCollection来自于页面的document等节点元素对象,主要是各种属性:

  • document.links:返回所有链接元素
  • docuement.forms:返回所有表单元素
  • document.images:返回所有图像元素
  • document.scripts:返回所有脚本元素
  • document.embeds:返回所有embed嵌入对象
  • Element.children:返回当前节点的所有子元素
const links = document.links
Object.prototype.toString.call(links) // '[object HTMLCollection]'
const linkArr = Array.from(links) // []
Array.isArray(linkArr) // true

以上代码,读取了页面所有的链接,返回的一个HTMLCollection类数组对象,可以转换成对应的数组,当前页面并不存在链接,所以返回的是空数组。

NodeList

通过以下方法或属性获取的节点列表(NodeList):

  • getElementsByTagName:返回所有拥有指定HTML标签名的节点
  • getElementsByClassName:返回所有拥有指定class类属性名的节点
  • getElementsByName:返回所有拥有指定name属性的节点
  • querySelectorAll:返回所有匹配给定选择器的节点
  • document.childNodes:返回所有子节点
const divList = document.querySelectorAll('div')
Array.isArray(divList) // false
Object.prototype.toString.call(divList) // '[object NodeList]'
divList.length // 4
const divArr = [...divList] //  [div, div#clickInput, div#name, div#dropArea]
Array.isArray(divArr) // true

以上代码,通过 querySelectorAll 读取了页面上所有的div,得到了一个NodeList对象,是一个类数组对象,可以通过扩展运算符转换成一个真正的数组。

其他DOM相关类数组对象

以下也是DOM操作中,常见的一些类数组对象:

  • document.styleSheets:返回所有样式表(StyleSheetList)
  • attributes:返回节点元素的所有属性(NamedNodeMap)
  • dataset:返回节点元素上的所有附加数据(DOMStringMap)
  • classList:返回节点元素上的所有样式类(DOMTokenList)

DOM中的对象都是由DOM-API提供给JavaScript调用的,因为不止JS要用,所以使用类数组较合适。

其他Web类数组对象

  • window
    window对象也拥有length,所以它也是类数组对象?
    是的,window的length属性表示页面拥有的frame/iframe的数量。
    所以也可以转换成数组:

    window.length // 0
    Array.from(window) // []
    

    当前页面没有frame,长度为0,转换成了空数组。

  • DataTransferItemList
    用于从拖拽或粘贴事件中读取到的 Datatransfer 对象的一个只读属性 items,同一级的只读属性还有 files,也是一个类数组对象 FileList,上面已有介绍。
    在粘贴事件中,可以通过该对象读取到粘贴的数据内容。

  • 数据存储
    浏览器中的数据存储机制,如 sessionStoragelocalStorage,他们其实也是类数组对象,拥有length属性,可以进行转换。

    localStorage.length // 2
    Array.from(localStorage) // [undefined, undefined]
    

    以上代码,就是对localStorage的处理,拥有两个值,但由于是字符串键值对,无法转成数字索引,所以数组两个元素都是 undefined。

总结

本文描述了什么是类数组对象,它的主要特点,以及如何创建一个类数组对象,还有将类数组对象转换成真正数组的几种方式,接着也介绍了前端开发中可能会遇到的已有的各种类数组对象。
事实上,绝大部分的类数组对象是不需要专门去转换为数组的,直接遍历操作即可,但深入掌握这些类数组的知识,也是前端开发中不可少的。文章来源地址https://www.toymoban.com/news/detail-468107.html

到了这里,关于一文搞懂前端的所有类数组类型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端传输数组类型到后端(附代码)

    通过问题Bug指引代码实战,结合实战问题,相应查漏补缺 前端传输数组给后端的时候,出现如下问题: 前端log请求如下: 且请求后端你的时候出现了服务器500error: 如果不使用 JSON 格式传输数据,而是使用普通的数组,可以考虑通过 POST 请求的 body 直接传输数组的形式 前端

    2024年04月17日
    浏览(28)
  • C语言:调整数组使奇数全部都位于偶数前面

    输入 一个 整数数组 , 实现 一个 函数 , 来 调整 该 数组中数字的顺序 使得 数组中所有的奇数 位于 数组的前半部分 , 所有 偶数 位于 数组的后半部分 。 ( 奇数在 数组 前 面, 偶数在 数组 后 面)                       ==========================================================

    2024年02月13日
    浏览(32)
  • 5个常见的前端手写功能:浅拷贝与深拷贝、函数柯里化、数组扁平化、数组去重、手写类型判断函数

    浅拷贝 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。 测试结果: 深拷贝 深拷贝是将

    2024年04月26日
    浏览(27)
  • (排序) 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 ——【Leetcode每日一题】

    难度:简单 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。 示例: 输入:nums = [1,2,3,4] 输出:[1,3,2,4] 注:[3,1,2,4] 也是正确的答案之一。 提示 : 0 = n u m s . l e n g t h = 50000 0 = nums.length = 50000 0 =

    2024年02月12日
    浏览(37)
  • 5分钟搞懂Kubernetes:轻松理解所有组件

    之前我曾经提到了一系列关于服务网格的内容。然而,我意识到有些同学可能对Kubernetes的了解相对较少,更不用说应用服务网格这个概念了。因此,今天我决定带着大家快速理解Kubernetes中的一些专有名词,以便在短时间内入门,并减少学习的时间。我将在接下来的5分钟内为

    2024年02月05日
    浏览(35)
  • 一文搞懂KMP算法!!!

    KMP算法是一种改进的 字符串匹配算法 ,由 D.E. K nuth , J.H. M orris 和 V.R. P ratt 提出的,因此人们称它为 克努特—莫里斯—普拉特 操作(简称 KMP 算法)。 KMP 算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。 具体实现就是通过一

    2024年02月07日
    浏览(33)
  • 一文搞懂HBA卡

    HBA卡是一个简称,准确叫法应该是:主机总线适配器(Host Bus Adapter,HBA),也叫做FC-HBA卡(俗称:光纤网卡)、iSCSI-HBA卡(RJ45接口)。这是一个在服务器和存储装置间提供输入/输出(I/O)处理和物理连接的电路板或集成电路适配器。由于传输协议的不同而出现,一般用在服务器的

    2024年02月04日
    浏览(38)
  • 一文搞懂 MySQL 索引

    1、MySQL 索引 简介 1.1、MySQL 索引 是什么?  索引是一个单独的、存储在 磁盘 上的 数据库结构 ,包含着对数据表里 所有记录的 引用指针。 1.2、 MySQL 索引 的存储类型有哪些?  MySQL中索引的存储类型有两种,即 BTree 和 Hash。 1.3、MySQL 索引 在哪里实现的?  索引是在存储

    2024年02月04日
    浏览(30)
  • 一文搞懂containerd

    在学习 Containerd 之前我们有必要对 Docker 的发展历史做一个简单的回顾,因为这里面牵涉到的组件实战是有点多,有很多我们会经常听到,但是不清楚这些组件到底是干什么用的,比如 libcontainer 、 runc 、 containerd 、 CRI 、 OCI 等等。 从 Docker 1.11 版本开始,Docker 容器运行就不

    2024年02月11日
    浏览(28)
  • 一文搞懂Nginx(上)

    是一个高性能的HTTP和反向代理web服务器,我们常用的功能有HTTP代理、负载均衡、动静分离、高可用集群,目前阶段我使用得比较多是就是代理和负载均衡,官方数据测试表明能够支持高达 50,000 个并发连接数的响应。占用的内存也特别的少。 优点: 1、负载均衡(可以减轻单

    2024年04月09日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包