我得到了reduce方法和rest参数的整个逻辑,但是我真的不明白0的重要性。非常感谢你提前!
const sum = (...args) => {
return args.reduce((a,b) => a + b, 0);
}
我得到了reduce方法和rest参数的整个逻辑,但是我真的不明白0的重要性。非常感谢你提前!
const sum = (...args) => {
return args.reduce((a,b) => a + b, 0);
}
ECMAScript 是一种动态类型/无类型/单一类型的编程语言(取决于您询问的对象)。Array.prototype.reduce
但是,查看此处的类型仍然有意义。
我将使用 TypeScript 语法,实际上,我将使用TypeScript 库中的定义,但实际语法并不重要:
reduce<U>(
callbackfn: (
previousValue: U,
currentValue: T,
currentIndex: number,
array: readonly T[]
) => U,
initialValue: U
): U;
将原始数组和当前索引传递给回调函数的事实是 ECMAScript 的一个奇怪之处,对于理解它是如何reduce
工作的并不是真正必要的,所以让我们摆脱这些:
reduce<U>(
callbackfn: (
previousValue: U,
currentValue: T,
) => U,
initialValue: U
): U;
另请注意,我们在这里有两个不同的类型参数:
T
是 的元素类型。Array<T>
U
是 的结果类型。reduce
所以,reduce
是一个接受三个参数的函数:
this
,即Array<T>
it 迭代的对象。U
T
U
U
。从概念上讲,reduce
它的作用是将一组值“减少”为单个值。重要的是要理解这个单一的结果值可以有任意类型。它不必与的元素类型相同Array
。
reduce
使用传递给它的归约函数来执行此操作。
所以,从概念上讲,reduce
回报是
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
initialValue,
this[0]
),
this[1]
),
this[2]
),
this[3]
),
this[4]
),
this[5]
),
this[6]
),
this[7]
)
// and so on …
或者,如果我们将回调函数编写为二元运算符ω
:
initialValue ω this[0] ω this[1] ω this[2] ω this[3] ω …
注意回调函数必须是左关联的,即等价于
(((((initialValue ω this[0]) ω this[1]) ω this[2]) ω this[3]) ω …)
许多集合库,ECMAScript 也不例外,也提供了reduce
不具有初始值的版本。在许多库中,这个版本有不同的名称(例如,在 Scala 中,有初始值的版本被称为foldLeft
,没有的版本被称为reduceLeft
,在 Haskell 中,有初始值的版本被称为foldl
,没有的版本被称为foldl1
)。在 ECMAScript 中,这是通过“重载”来处理的,即您可以简单地省略initialValue
参数。
如果省略了初始值,我们改为从集合的第一个元素开始,即
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
callbackfn(
this[0],
this[1]
),
this[2]
),
this[3]
),
this[4]
),
this[5]
),
this[6]
),
this[7]
)
// and so on …
或写为运算符
this[0] ω this[1] ω this[2] ω this[3] ω …
但是,这有一个重要的后果!我们的操作符/回调函数现在需要接受两个T
s 并返回一个T
,不再有办法获得与元素类型不同的结果类型。
它还有另一个重要的后果:reduce
不再适用于空集合。
因此,这将是您需要提供初始值的两个原因:
reduce
使用空集合。在这种特殊情况下,第一个原因不适用:该函数显然是为了减少 an Array<number>
to number
。但是第二个原因是相关的:您不想强制函数的客户端必须检查集合是否为空。客户应该能够打电话
sum(...someArray)
不用担心是否someArray
为空。
将类型更改为任意类型的能力对于reduce
. 事实证明这reduce
是一个强大的功能:它可以通过迭代集合来完成您可以做的所有事情。换句话说:你可以从 ECMAScript 中删除except的所有方法,也可以删除and ,你仍然可以通过迭代集合来做所有可能做的事情。(好吧,我猜你需要一种方法来向数组中添加一些东西,所以我们也保留一下。)Array.prototype
reduce
for … of
for … in
push
这里只是一个实现Array.prototype.map
using的例子Array.prototype.reduce
:
Array.prototype.map = function map(callbackFn) {
return this.reduce(
(previousValue, currentValue) =>
previousValue.push(callbackFn(currentValue)),
[]
);
}
在这里您可以看到我们可以更改类型这一事实很重要,因为我们从 an 开始Array<T>
,但我们不想要T
a 结果,我们想要一个Array<U>
。这也表明“reduce
将集合缩减为单个值”这句话并不意味着结果必须是一个简单的值。结果值可以随心所欲……在这种情况下,是另一个数组。