-4

我得到了reduce方法和rest参数的整个逻辑,但是我真的不明白0的重要性。非常感谢你提前!

const sum = (...args) => {
   return args.reduce((a,b) => a + b, 0);
}
4

1 回答 1

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是一个接受三个参数的函数:

  • invisible this,即Array<T>it 迭代的对象。
  • 一个结合 a和 a并产生一个新的函数UTU
  • 类型的初始值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] ω …

但是,这有一个重要的后果!我们的操作符/回调函数现在需要接受两个Ts 并返回一个T,不再有办法获得与元素类型不同的结果类型。

它还有另一个重要的后果:reduce不再适用于空集合。

因此,这将是您需要提供初始值的两个原因:

  • 您想要转换类型。
  • 您希望reduce使用空集合。

在这种特殊情况下,第一个原因不适用:该函数显然是为了减少 an Array<number>to number。但是第二个原因是相关的:您不想强制函数的客户端必须检查集合是否为空。客户应该能够打电话

sum(...someArray)

不用担心是否someArray为空。

将类型更改为任意类型的能力对于reduce. 事实证明这reduce是一个强大的功能:它可以通过迭代集合来完成您可以做的所有事情。换句话说:你可以从 ECMAScript 中删除except的所有方法,也可以删除and ,你仍然可以通过迭代集合来做所有可能做的事情。(好吧,我猜你需要一种方法来向数组中添加一些东西,所以我们也保留一下。)Array.prototypereducefor … offor … inpush

这里只是一个实现Array.prototype.mapusing的例子Array.prototype.reduce

Array.prototype.map = function map(callbackFn) {
    return this.reduce(
        (previousValue, currentValue) =>
            previousValue.push(callbackFn(currentValue)),
        []
    );
}

在这里您可以看到我们可以更改类型这一事实很重要,因为我们从 an 开始Array<T>,但我们不想要Ta 结果,我们想要一个Array<U>。这也表明“reduce将集合缩减为单个值”这句话并不意味着结果必须是一个简单的值。结果值可以随心所欲……在这种情况下,是另一个数组。

于 2021-12-30T21:33:52.660 回答