TypeError: Reduce of empty array with no initial value

JavaScript 异常 "reduce of empty array with no initial value" 发生在使用了 reduce 函数时。

消息

TypeError: Reduce of empty array with no initial value (V8-based & Firefox & Safari)

错误类型

TypeError

哪里出错了?

在 JavaScript 中,有几个 reduce 函数:

这些函数可选地接受一个 initialValue(它将作为 callback 第一次调用的第一个参数)。但是,如果未提供初始值,它将使用 ArrayTypedArray 的第一个元素作为初始值。当提供空数组时会引发此错误,因为在这种情况下无法返回初始值。

示例

无效案例

当与 filter(Array.prototype.filter(), TypedArray.prototype.filter())结合使用时,此问题经常出现,filter 会删除列表中的所有元素。因此,没有元素可用作初始值。

js
const ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // removes all elements
  .reduce((x, y) => x + y); // no more elements to use for the initial value.

同样,如果选择器中有拼写错误,或者列表中元素的数量出乎意料,也可能发生同样的问题。

js
const names = document.getElementsByClassName("names");
const name_list = Array.prototype.reduce.call(
  names,
  (acc, name) => `${acc}, ${name}`,
);

有效情况

这些问题可以通过两种不同的方式解决。

一种方法是实际提供一个 initialValue 作为操作符的“中性元素”,例如加法的 0,乘法的 1,或连接的空字符串。

js
const ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // removes all elements
  .reduce((x, y) => x + y, 0); // the initial value is the neutral element of the addition

另一种方法是处理空情况,可以在调用 reduce 之前,或者在添加一个意外的虚拟初始值后在回调中处理。

js
const names = document.getElementsByClassName("names");

let nameList1 = "";
if (names.length >= 1) {
  nameList1 = Array.prototype.reduce.call(
    names,
    (acc, name) => `${acc}, ${name}`,
  );
}
// nameList1 === "" when names is empty.

const nameList2 = Array.prototype.reduce.call(
  names,
  (acc, name) => {
    if (acc === "")
      // initial value
      return name;
    return `${acc}, ${name}`;
  },
  "",
);
// nameList2 === "" when names is empty.

另见