Array.from

JavaScript

Array.from 是 JavaScript 中一个较新的 API,可以将一个类数组或可迭代对象转化成一个真正的数组。

类数组(array-like)常见于 DOM API 中取到的数据,比如 .querySelectorAll。得到的结果有 .length 属性,也可以通过下标获取到数据,但是本身却不是一个数组,没有 Array.prototype 上的 API 可以直接用。

可迭代对象则是指那些定义了 Symbol.iterator 属性的对象。

Array.from 可以将上述的两种对象直接转化成一个标准的数组:

const iterable = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
  },
};
console.log(Array.from(iterable)); // => [1, 2];

const arrayLike = document.querySelectorAll('span');
console.log(Array.from(arrayLike)); // => [span, span, ...]

除了上述常见的应用之外,Array.from 还有一些特殊的应用。

首先,只要指定了 length 属性,Array.from 就可以创建一个数组。这一行为可以用来创建一个指定长度的数组:

Array.from({ length: 5 }).map((_, i) => i);
// => [0, 1, 2, 3, 4]

其次,Array.from 函数其实接受不止一个参数。第二个参数是一个 map 函数,第三个参数是 thisArg,用于指定 map 函数的 this 对象。有了这个 map 函数的支持,上面这个例子就可以进一步改写成:

Array.from({ length: 5 }, (_, i) => i);

在转化 DOM 类数组的时候,直接通过指定 map 函数进行进一步的转化,是比较方便的。可以省略一个 .map 函数的嵌套,也节省一个中间数组对象的创建。

Array.prototype.map 函数可以指定 thisArg,在 Array.from 中也可以通过第三个参数指定 thisArg。以下是一个例子:

const mapper = {
  shift: 1,
  run(_, i) {
    return this.shift + i;
  },
};
Array.from({ length: 5 }, mapper.run, mapper);
// => [1, 2, 3, 4, 5];

上述写法等价于:

Array.from({ length: 5 }).map(mapper.run, mapper);