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

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

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

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

这在 DOM 中甚为常见,如各类元素检索 API 返回的都是类数组,如 document.getElementsByTagNamedocument.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) 属性值app

拥有 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 = {
  0: 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]
复制代码

我是山月,能够加我微信 shanyue94 与我交流,备注交流。另外能够关注个人公众号【全栈成长之路】

若是你对全栈面试,前端工程化,graphql,devops,我的服务器运维以及微服务感兴趣的话,能够关注我
相关文章
相关标签/搜索