你真的会将类数组转化为数组吗

简介: 首先,什么是类数组(Array Like)?一个简单的定义,如果一个对象有 length 属性值,则它就是类数组那常见的类数组有哪些呢?这在 DOM 中甚为常见,如各种元素检索 API 返回的都是类数组,如 document.getElementsByTagName,document.querySelectorAll 等等。除了 DOM API 中,常见的 function 中的 arguments 也是类数组那如何把类数组转化为数组呢?这是类数组操作时一个典型的场景,也是一个典型的面试题以下我们将以 { length: 3 } 来指代类数组,来作为演示节选自 日文 【

首先,什么是类数组(Array Like)?

一个简单的定义,如果一个对象有 length 属性值,则它就是类数组

那常见的类数组有哪些呢?

这在 DOM 中甚为常见,如各种元素检索 API 返回的都是类数组,如 document.getElementsByTagName,document.querySelectorAll 等等。除了 DOM API 中,常见的 function 中的 arguments 也是类数组

那如何把类数组转化为数组呢?这是类数组操作时一个典型的场景,也是一个典型的面试题

以下我们将以 { length: 3 } 来指代类数组,来作为演示

节选自 日文 【Q168】在 js 中如何把类数组转化为数组。另外这里有更多的 前端面试题,欢迎交流

ES6+
ES6 中有现成的 API:Array.from,极为简单

// [undefined, undefined, undefined]
Array.from({ length: 3 })
复制代码
除了 Array.from 还有更简单的运算符 ... 扩展运算符,不过它只能作用于 iterable 对象,即拥有 Symbol(Symbol.iterator) 属性值

拥有 Symbol(Symbol.iterator) 属性值,意味着可以使用 for of 来循环迭代

// 适用于 iterable 对象
[...document.querySelectorAll('div')]
复制代码
但是严格意义上来说,它不能把类数组转化为数组,如 { length: 3 }。它将会抛出异常

// Uncaught TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
[...{length: 3}]
复制代码
ES5
在此之前,我们先不使用 { length: 3 },使用以下数据来代表类数组

const arrayLike = {
: 3,
1: 4,
2: 5,
length: 3
}
复制代码
在 ES5 中可以借用 Array API 通过 call/apply 改变 this 或者 arguments 来完成转化。

最常见的转换是 Array.prototype.slice

Array.prototype.slice.call(arrayLike)
复制代码
当然由于借用 Array API,一切以数组为输入,并以手机靓号买卖数组为输出的 API 都可以来做数组转换,如

Array (借用 arguments)
Array.prototype.concat (借用 arguments)
Array.prototype.slice (借用 this)
Array.prototype.map (借用 this)
Array.prototype.filter (借用 this)
Array.apply(null, arrayLike)
Array.prototype.concat.apply([], arrayLike)
Array.prototype.slice.call(arrayLike)
Array.prototype.map.call(arrayLike, x => x)
Array.prototype.filter.call(arrayLike, x => 1)
复制代码
此时一切正常,但是忘了一个特例,稀疏数组。在此之前,先做一个题,以下代码输出多少

// 该代码输出多少
Array(100).map(x => 1)
复制代码
参考 Array(100).map(x => 1) 结果是多少

稀疏数组 (sparse array)
使用 Array(n) 将会创建一个稀疏数组,为了节省空间,稀疏数组内含非真实元素,在控制台上将以 empty 显示,如下所示

[,,,] 与 Array(3) 都将返回稀疏数组

[,,,]
[empty × 3]
Array(3)
[empty × 3]
复制代码
当类数组为 { length: 3 } 时,一切将类数组做为 this 的方法将都返回稀疏数组,而将类数组做为 arguments 的方法将都返回密集数组

总结
由上总结,把类数组转化成数组最靠谱的方式是以下三个

Array.from(arrayLike)
Array.apply(null, arrayLike)
Array.prototype.concat.apply([], arrayLike)
复制代码
以下几种方法需要考虑稀疏数组的转化

Array.prototype.filter.call(divs, x => 1)
Array.prototype.map.call(arrayLike, x => x)
Array.prototype.filter.call(arrayLike, x => 1)
复制代码
以下方法要注意是否是 iterable object

[...arrayLike]
复制代码

目录
相关文章
|
6月前
数组相关方法?
数组相关方法?
|
18小时前
|
JavaScript
类数组是什么
类数组是什么
6 0
|
2天前
|
JavaScript 前端开发 索引
数组相关方法
数组相关方法
10 0
|
2天前
|
JSON JavaScript 前端开发
揭秘类数组对象:形似数组,超越数组!(下)
揭秘类数组对象:形似数组,超越数组!(下)
|
2天前
|
JavaScript 前端开发 索引
揭秘类数组对象:形似数组,超越数组!(上)
揭秘类数组对象:形似数组,超越数组!(上)
|
8月前
|
存储 机器学习/深度学习 Java
Java数组的定义和使用(一篇带你搞定数组)
Java数组的定义和使用(一篇带你搞定数组)
196 0
|
9月前
数组与集合的转换
数组与集合的转换
32 0
|
6月前
|
前端开发
数组常用的几个方法
数组常用的几个方法
23 0
|
9月前
数组的相关方法
数组的相关方法
25 0
|
9月前
|
存储 索引
数组与字符串的关系【了解一下】
数组与字符串的关系【了解一下】
96 0