类数组转化为数组的方法
详解在 JavaScript 中将类数组对象转换为真正数组的多种实现方式
问题
在 JavaScript 中,类数组对象(Array-like Object)是指具有 length 属性和索引元素,但不具备数组方法的对象。常见的类数组对象包括:
arguments对象- DOM 方法返回的
NodeList HTMLCollection- 字符串等
我们需要将这些类数组对象转换为真正的数组,以便使用数组的各种方法(如 map、filter、forEach 等)。
解答
// 方法1: Array.from()(ES6推荐)
function toArray1(arrayLike) {
return Array.from(arrayLike);
}
// 方法2: 扩展运算符(ES6)
function toArray2(arrayLike) {
return [...arrayLike];
}
// 方法3: Array.prototype.slice.call()
function toArray3(arrayLike) {
return Array.prototype.slice.call(arrayLike);
}
// 方法4: [].slice.call()(简写形式)
function toArray4(arrayLike) {
return [].slice.call(arrayLike);
}
// 方法5: Array.prototype.concat.apply()
function toArray5(arrayLike) {
return Array.prototype.concat.apply([], arrayLike);
}
// 方法6: 手动遍历(兼容性最好)
function toArray6(arrayLike) {
const arr = [];
for (let i = 0; i < arrayLike.length; i++) {
arr.push(arrayLike[i]);
}
return arr;
}
// 方法7: Array.prototype.map()
function toArray7(arrayLike) {
return Array.prototype.map.call(arrayLike, item => item);
}
// 方法8: Array.of() + 扩展运算符
function toArray8(arrayLike) {
return Array.of(...arrayLike);
}
使用示例
// 示例1: 转换 arguments 对象
function testArguments() {
console.log('原始 arguments:', arguments);
console.log('是否为数组:', Array.isArray(arguments)); // false
const arr = Array.from(arguments);
console.log('转换后:', arr);
console.log('是否为数组:', Array.isArray(arr)); // true
// 现在可以使用数组方法
const doubled = arr.map(x => x * 2);
console.log('使用 map 方法:', doubled);
}
testArguments(1, 2, 3, 4, 5);
// 示例2: 转换 NodeList
const divs = document.querySelectorAll('div');
console.log('NodeList:', divs);
console.log('是否为数组:', Array.isArray(divs)); // false
const divsArray = [...divs];
console.log('转换后的数组:', divsArray);
divsArray.forEach(div => {
console.log(div.textContent);
});
// 示例3: 转换字符串
const str = 'hello';
const strArray = Array.from(str);
console.log('字符串转数组:', strArray); // ['h', 'e', 'l', 'l', 'o']
// 示例4: 转换自定义类数组对象
const arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
console.log('类数组对象:', arrayLike);
const realArray = Array.from(arrayLike);
console.log('转换后:', realArray); // ['a', 'b', 'c']
// 示例5: Array.from() 的映射功能
const numbers = { 0: 1, 1: 2, 2: 3, length: 3 };
const doubled = Array.from(numbers, x => x * 2);
console.log('转换并映射:', doubled); // [2, 4, 6]
// 示例6: 性能对比测试
const largeArrayLike = { length: 10000 };
for (let i = 0; i < 10000; i++) {
largeArrayLike[i] = i;
}
console.time('Array.from');
Array.from(largeArrayLike);
console.timeEnd('Array.from');
console.time('扩展运算符');
[...largeArrayLike];
console.timeEnd('扩展运算符');
console.time('slice.call');
Array.prototype.slice.call(largeArrayLike);
console.timeEnd('slice.call');
关键点
-
Array.from() 是最推荐的方法:语义清晰,功能强大,支持第二个参数进行映射操作,类似
map方法 -
扩展运算符简洁优雅:适用于具有迭代器接口的类数组对象,代码简洁,但不支持纯类数组对象(只有 length 和索引的对象)
-
slice.call() 兼容性好:适用于 ES5 环境,是传统的转换方式,兼容性最佳
-
注意类数组对象的特征:必须具有
length属性和数字索引,否则转换结果可能不符合预期 -
性能考虑:对于大量数据,
Array.from()和扩展运算符性能较好,手动遍历在某些场景下可能更快 -
迭代器协议:扩展运算符要求对象实现了迭代器协议(Symbol.iterator),而
Array.from()既支持可迭代对象也支持类数组对象 -
实际应用场景:在处理 DOM 操作、函数参数、第三方库返回的类数组对象时经常需要进行转换
-
ES6+ 环境优先使用:
Array.from()或扩展运算符,代码更现代化和可读
目录