面试题:什么是 JavaScript 的类数组对象?如何转化为数组?

什么是 JavaScript 的类数组对象?

类数组对象(Array-like Object) 指的是一个普通对象,它具备以下两个关键特征,使其行为类似于数组,但不是真正的 Array 实例:

  1. 具有 length 属性:这个属性的值通常是一个非负整数,表示“元素”的数量。
  2. 拥有从 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

常见的类数组对象

  1. arguments 对象:函数内部的特殊对象,包含所有传入的实参。
function example() {
     console.log(arguments); // { '0': 'a', '1': 'b', length: 2 }
     console.log(Array.isArray(arguments)); // false
   }
   example('a', 'b');
  1. 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 可迭代
  1. HTMLCollection:由 document.getElementsByClassName()document.getElementsByTagName() 返回的集合。
const collection = document.getElementsByClassName('my-class');
   console.log(collection instanceof HTMLCollection); // true
  1. 字符串(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 方法)。现代浏览器中的 argumentsNodeList 等通常都是可迭代的。

function example() {
  // 将 arguments 转换为数组
  const args = [...arguments];
  args.forEach(arg => console.log(arg));
}
example('x', 'y');

方法 3:Array.prototype.slice.call()

经典且兼容性好的方法,利用 callapply 改变 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
喜欢就支持一下吧
点赞7 分享