简而言之:[a,b,c].reduce(...) 和 [b,c].reduce(..., a) 有时是同一个东西。更好的思考方式是,initialValue 实际上是您计算的第一个中间结果。
reduce 的基本工作
要更好地了解 reduce 的工作原理,请使用以下 sum(a,b) 函数,该函数会为它执行的每个操作记录类似 a+b=c 的文本。
function sum(a,b) {
const c = a + b;
console.log(`${a} + ${b} => ${c}`)
return c;
}
const arr = [1,2,4,8];
const result = arr.reduce(sum);
console.log(`result=${result}`)
这会打印出1+2=3、3+4=7、7+8=15,最后是result=15。
角落案例:1 个元素
const arr = [1];
const result= arr.reduce(sum);
console.log(`result=${result}`)
如果数组中只有一个元素。然后它甚至根本不会调用提供的函数。 它只会返回单个元素。所以在这种情况下,它只会打印result=1。
角落案例:0 个元素
const arr = [];
const result = arr.reduce(sum);
console.log(`result=${result}`)
如果没有元素也没有初始值,那么它只会抛出一个错误:Uncaught TypeError: Reduce of empty array with no initial value
如何准备空数组:
当然你可以在你的代码中添加一个检查来检查你的数组的length。
一个非常可靠的解决方法是在数组前面添加一个初始值。
const arr = [];
const arr2 = [0, ...arr];
const result = arr2.reduce(sum)
initialValue 参数提供了更好的解决方案。很容易说initialValue 实际上做了同样的事情。那是不正确的。
const result = arr.reduce(sum, 0);
然而,在本示例的上下文中,两者都导致相同的结果。然而,实际上initialValue并不是一个输入值,而更像是初始总和。
使用对象:
只有当您开始使用reduce 进行更复杂的转换时,才会有一个小的区别。
const inputs = [{value: 1}, {value: 2}, {value:3}];
const total = inputs.reduce((sum, input) => sum + input.value, 0);
上面的示例再次创建了一个总计,但这次它从属性value 中提取输入。我们有一个对象的输入和一个数字结果。在这种示例中,initialValue 根本不是可选的。这是强制性的。
想想如果在这个例子中没有initialValue 会发生什么。 sum 在第一次迭代中的值是多少?
sum 实际上是 {value: 1},它甚至不是一个数字。
因此,在此示例中,很明显 initialValue 实际上是您计算的第一个中间结果。