类型错误:减少没有初始值的空数组
使用 reduce 函数时出现 JavaScript 异常 "减少没有初始值的空数组"。
¥The JavaScript exception "reduce of empty array with no initial value" occurs when a reduce function is used.
信息
错误类型
什么地方出了错?
¥What went wrong?
在 JavaScript 中,有几个 reduce 函数:
¥In JavaScript, there are several reduce functions:
Array.prototype.reduce()
、Array.prototype.reduceRight()
和TypedArray.prototype.reduce()
,TypedArray.prototype.reduceRight()
).
这些函数可以选择采用 initialValue
(它将用作 callback
第一次调用的第一个参数)。但是,如果没有提供初始值,它将使用 Array
或 TypedArray
的第一个元素作为初始值。当提供空数组时会引发此错误,因为在这种情况下无法返回初始值。
¥These functions optionally take an initialValue
(which will be used as the
first argument to the first call of the callback
). However, if no initial
value is provided, it will use the first element of the Array
or
TypedArray
as the initial value. This error is raised when an empty array
is provided because no initial value can be returned in that case.
示例
无效案例
¥Invalid cases
当与过滤器(Array.prototype.filter()
、TypedArray.prototype.filter()
)结合使用时,此问题会经常出现,该过滤器将删除列表中的所有元素。因此没有留下任何一个可以用作初始值。
¥This problem appears frequently when combined with a filter
(Array.prototype.filter()
, TypedArray.prototype.filter()
)
which will remove all elements of the list. Thus leaving none to be used as the initial
value.
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.
同样,如果选择器中存在拼写错误,或者列表中的元素数量超出预期,也可能会发生相同的问题:
¥Similarly, the same issue can happen if there is a typo in a selector, or an unexpected number of elements in a list:
const names = document.getElementsByClassName("names");
const name_list = Array.prototype.reduce.call(
names,
(acc, name) => acc + ", " + name,
);
有效案例
¥Valid cases
这些问题可以通过两种不同的方式解决。
¥These problems can be solved in two different ways.
一种方法是实际提供 initialValue
作为运算符的中性元素,例如用于加法的 0、用于乘法的 1 或用于连接的空字符串。
¥One way is to actually provide an initialValue
as the neutral element of
the operator, such as 0 for the addition, 1 for a multiplication, or an empty string for
a concatenation.
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
之前或在添加意外的虚拟初始值之后的回调中处理空情况。
¥Another way would be to handle the empty case, either before calling
reduce
, or in the callback after adding an unexpected dummy initial value.
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.