伪数组与真数组的转换

什么是伪数组以及转换为真数组的几种方法

问题

什么是伪数组(ArrayLike),如何转为真数组?

解答

什么是伪数组

伪数组是具有 length 属性和索引元素,但没有数组方法的对象。

// 常见的伪数组
const arrayLike = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

// DOM 集合是伪数组
const divs = document.querySelectorAll('div'); // NodeList
const inputs = document.getElementsByTagName('input'); // HTMLCollection

// 函数的 arguments 是伪数组
function test() {
  console.log(arguments); // Arguments 对象
  console.log(arguments.length); // 可以访问 length
  // arguments.map() // 报错,没有数组方法
}

转换方法

1. Array.from()(推荐)

const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };

const arr = Array.from(arrayLike);
console.log(arr); // ['a', 'b', 'c']
console.log(Array.isArray(arr)); // true

// 可以同时进行映射
const arr2 = Array.from(arrayLike, item => item.toUpperCase());
console.log(arr2); // ['A', 'B', 'C']

2. 展开运算符

// 适用于可迭代对象(NodeList、arguments 等)
const divs = document.querySelectorAll('div');
const arr = [...divs];

function test() {
  const args = [...arguments];
  console.log(Array.isArray(args)); // true
}

// 注意:普通对象不可迭代,会报错
const obj = { 0: 'a', 1: 'b', length: 2 };
// [...obj] // TypeError: obj is not iterable

3. Array.prototype.slice.call()

const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };

const arr = Array.prototype.slice.call(arrayLike);
// 或简写
const arr2 = [].slice.call(arrayLike);

console.log(arr); // ['a', 'b', 'c']

4. Array.prototype.concat.apply()

const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };

const arr = Array.prototype.concat.apply([], arrayLike);
console.log(arr); // ['a', 'b', 'c']

判断是否为伪数组

function isArrayLike(obj) {
  // 排除 null、undefined 和 window
  if (obj == null || obj === window) return false;
  
  // 排除函数(函数也有 length 属性)
  if (typeof obj === 'function') return false;
  
  const length = obj.length;
  
  // length 必须是非负整数
  return typeof length === 'number' 
    && length >= 0 
    && Number.isInteger(length);
}

console.log(isArrayLike({ 0: 'a', length: 1 })); // true
console.log(isArrayLike([1, 2, 3])); // true
console.log(isArrayLike('hello')); // true(字符串也是伪数组)
console.log(isArrayLike({ name: 'test' })); // false

关键点

  • 伪数组有 length 和索引,但没有 pushmap 等数组方法
  • Array.from() 是最通用的转换方法,支持映射函数
  • 展开运算符 [...] 只能用于可迭代对象
  • argumentsNodeListHTMLCollection 是常见的伪数组
  • 字符串也是伪数组,可以用索引访问字符