类数组(Array-like object)在 JavaScript 中是指那些具有某些类似于数组的特性,但并不是真正数组的对象。
它们通常具备以下特点:
-
数字索引:类数组对象拥有按顺序排列的数字键(索引),从
0
开始,就像数组一样。 -
length
属性:类数组通常有一个length
属性,表示其中元素的数量。这个属性会根据类数组中最后一个数字键来确定。 -
非负整数索引:除了
length
之外,类数组的其他属性通常是正整数或零,作为索引使用。 -
不是真正的数组:尽管有上述特性,类数组并不继承自
Array.prototype
,因此它们不具有数组的内置方法,如push()
,pop()
,forEach()
等。
常见的类数组对象
-
arguments
对象:这是函数内部的一个本地变量,包含了传递给该函数的所有参数。它是典型的类数组对象,在 ES6 之前广泛用于处理不定数量的参数。 -
NodeList:由 DOM 方法如
document.querySelectorAll()
或document.getElementsByTagName()
返回的对象。在现代浏览器中,NodeList
可能是活的(live)或静态的(static)。虽然它们看起来像数组,并且在某些情况下可以像数组一样被遍历,但它们并不是真正的数组。 -
HTMLCollection:与
NodeList
类似,HTMLCollection
是由 DOM 方法如document.getElementsByClassName()
或document.getElementsByName()
返回的对象。它也是一个类数组对象,包含一组 HTML 元素。 -
字符串匹配结果:当使用
String.prototype.match()
方法并且提供了全局标志g
时,返回的结果是一个类数组对象,而不是一个普通的数组。
将类数组转换为数组
由于类数组缺少数组的方法,有时候我们需要将它们转换为真正的数组以便利用数组提供的丰富功能。以下是几种常见的转换方式:
-
Array.from()
:let arrayLike = {0: 'a', 1: 'b', 2: 'c', length: 3}; let arr = Array.from(arrayLike);
-
扩展运算符(Spread Operator):
let arr = [...arrayLike];
-
Array.prototype.slice.call()
(适用于旧版浏览器):let arr = Array.prototype.slice.call(arrayLike);
-
apply
方法(另一种旧版浏览器兼容的方式):let arr = [].slice.apply(arrayLike);
注意事项
-
性能:对于非常大的类数组,使用
Array.from
或扩展运算符可能会有性能上的考虑,因为它们需要创建新的数组实例。如果只是想借用数组的方法,可以直接调用Array.prototype
上的方法并使用call
或apply
来操作类数组,而不需要创建新数组。 -
不可变性:一些类数组对象,比如
NodeList
和HTMLCollection
,可能是“活”的,这意味着它们会自动更新以反映DOM的变化。当你将它们转换为数组后,得到的是一个快照,后续的DOM变化不会影响到这个数组。
通过理解类数组的概念及其与真实数组的区别,你可以更好地选择何时以及如何在JavaScript代码中使用这些对象。