什么是 JavaScript 的类数组对象?
类数组对象(Array-like Object) 指的是一个普通对象,它具备以下两个关键特征,使其行为类似于数组,但不是真正的 Array
实例:
- 具有
length
属性:这个属性的值通常是一个非负整数,表示“元素”的数量。 - 拥有从
0
开始的数字索引属性:可以通过obj[0]
,obj[1]
,obj[2]
… 这样的方式访问其“元素”。
关键区别:
- 原型链:真正的数组对象的原型链是
array -> Array.prototype -> Object.prototype
。而类数组对象的原型链通常是arrayLike -> Object.prototype
,它没有继承Array.prototype
,因此无法直接使用push
,pop
,forEach
,map
等数组方法。 - 构造函数:
Array.isArray(arrayLike)
返回false
。
常见的类数组对象
arguments
对象:函数内部的特殊对象,包含所有传入的实参。
function example() {
console.log(arguments); // { '0': 'a', '1': 'b', length: 2 }
console.log(Array.isArray(arguments)); // false
}
example('a', 'b');
NodeList
:由document.querySelectorAll()
或element.childNodes
返回的节点集合。
const nodeList = document.querySelectorAll('div');
console.log(nodeList instanceof NodeList); // true
console.log(Array.isArray(nodeList)); // false
// nodeList.forEach(...) // 在旧浏览器可能报错,现代浏览器 NodeList 可迭代
HTMLCollection
:由document.getElementsByClassName()
或document.getElementsByTagName()
返回的集合。
const collection = document.getElementsByClassName('my-class');
console.log(collection instanceof HTMLCollection); // true
- 字符串(String):字符串也具有
length
和数字索引,可以被视为类数组。
const str = "hello";
console.log(str.length); // 5
console.log(str[0]); // 'h'
console.log(Array.isArray(str)); // false
如何将类数组对象转化为数组?
由于类数组对象不能直接使用数组方法,通常需要先将其转换为真正的数组。以下是几种常用方法:
方法 1:Array.from()
(推荐 – ES6)
最现代、最语义化的方法。可以将任何类数组对象或可迭代对象转换为数组。
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
// 转换为数组
const arr = Array.from(arrayLike);
console.log(arr); // ['a', 'b']
console.log(Array.isArray(arr)); // true
// 还可以结合 map 函数
const doubled = Array.from(arrayLike, item => item + item);
// ['aa', 'bb']
方法 2:扩展运算符 ...
(推荐 – ES6)
利用扩展运算符将类数组对象“展开”到一个新数组中。前提是该类数组对象是可迭代的(实现了 Symbol.iterator
方法)。现代浏览器中的 arguments
、NodeList
等通常都是可迭代的。
function example() {
// 将 arguments 转换为数组
const args = [...arguments];
args.forEach(arg => console.log(arg));
}
example('x', 'y');
方法 3:Array.prototype.slice.call()
经典且兼容性好的方法,利用 call
或 apply
改变 slice
方法的 this
指向。
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
// 转换为数组
const arr = Array.prototype.slice.call(arrayLike);
// 或者使用 apply
// const arr = Array.prototype.slice.apply(arrayLike);
console.log(arr); // ['a', 'b']
方法 4:Array.prototype.concat.apply()
另一种借用数组方法的方式。
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
const arr = Array.prototype.concat.apply([], arrayLike);
console.log(arr); // ['a', 'b']
方法 5:传统 for
循环
最基础、兼容性最好的方法,手动遍历并填充新数组。
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
const arr = [];
for (let i = 0; i < arrayLike.length; i++) {
arr[i] = arrayLike[i];
}
console.log(arr); // ['a', 'b']
总结
- 类数组对象:有
length
和数字索引的普通对象,但不是Array
实例,无法使用数组方法。 - 常见例子:
arguments
,NodeList
,HTMLCollection
, 字符串。 - 转换为数组的方法:
- 现代推荐:
Array.from(arrayLike)
或[...arrayLike]
(如果可迭代)。 - 经典兼容:
Array.prototype.slice.call(arrayLike)
。 - 基础方法:手动
for
循环。
- 现代推荐:
在现代 JavaScript 开发中,优先使用 Array.from()
或扩展运算符 ...
来进行转换。
THE END