首先,什麼是類數組(Array Like)?前端
一個簡單的定義,若是一個對象有 length
屬性值,則它就是類數組git
那常見的類數組有哪些呢?es6
這在 DOM 中甚爲常見,如各類元素檢索 API 返回的都是類數組,如 document.getElementsByTagName
,document.querySelectorAll
等等。除了 DOM API 中,常見的 function
中的 arguments
也是類數組github
那如何把類數組轉化爲數組呢?這是類數組操做時一個典型的場景,也是一個典型的面試題面試
如下咱們將以 { length: 3 }
來指代類數組,來做爲演示數組
節選自 日文 【Q168】在 js 中如何把類數組轉化爲數組。另外這裏有更多的 前端面試題,歡迎交流app
ES6
中有現成的 API:Array.from
,極爲簡單this
// [undefined, undefined, undefined] Array.from({ length: 3 })
除了 Array.from
還有更簡單的運算符 ...
擴展運算符,不過它只能做用於 iterable
對象,即擁有 Symbol(Symbol.iterator)
屬性值es5
擁有 Symbol(Symbol.iterator)
屬性值,意味着可使用 for of
來循環迭代spa
// 適用於 iterable 對象 [...document.querySelectorAll('div')]
可是嚴格意義上來講,它不能把類數組轉化爲數組,如 { length: 3 }
。它將會拋出異常
// Uncaught TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator)) [...{length: 3}]
在此以前,咱們先不使用 { 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(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]