【问题标题】:How are parameters get mapped in reduce function?参数如何在reduce函数中映射?
【发布时间】:2019-07-01 03:36:46
【问题描述】:

MDN 定义 reduce() 如下:

reduce() 方法对数组的每个元素执行(您提供的)reducer 函数,从而产生单个输出值。

我们不要想当然,只分析以下语句的语法:

const array1 = [1, 2, 3, 4];
const reducer = (y, x) => y + x;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
  1. reducer 是一个函数,它接受两个参数并返回它们的总和
  2. reducer 在数组的每个元素上执行,但“数组的每个元素”只是一个参数,为什么我可以假设 SUM 是另一个参数并缓存在某个地方等待下一次添加操作?为什么我可以假设 reduce 在最后返回总和?

有人可以回答这些问题吗?来自其他语言背景的人,例如C里面也有函数的概念。我经常对 Javascript 的语法感到困惑。

这就是我看到时更加困惑的原因:

const pipeline = [
  array => { array.pop(); return array; },
  array => array.reverse()
];

pipeline.reduce((xs, f) => f(xs), [1, 2, 3]);

再次因为,根据 MDN,reduce() 方法对数组的每个元素执行(您提供的)reducer 函数,从而产生单个输出值。

只有这一次,

reducer: (xs, f) => f(xs)

累加器:[1, 2, 3]

array1:管道

那么我们如何解释它的行为类似于我们用英语的第一个例子?

【问题讨论】:

  • 您过早停止阅读。 “你的 reducer 函数的返回值被分配给累加器,它的值在整个数组的每次迭代中都会被记住,并最终成为最终的单一结果值。”
  • 1。 reducer 接受四个参数,前两个是强制性的(请参阅缺少方括号)。你可以传递更多,就像在任何 JS 函数中一样,但它们将被忽略。 2Array.prototype.reduce 不是求和,你可以做其他一些事情,比如计数、计算平均值、展平等。Reduce 是关于在迭代数组中的每个元素时使用累加器
  • @RaymondChen 谢谢,雷蒙德。我的坏习惯。过早停止阅读:(
  • 为什么杰克的回答被删了?!我试图提出后续问题
  • @RaymondChen 在第二个例子中,pipeline 是要归约的数组,(xs, f) => f(xs) 是归约函数,[1, 2, 3] 是累加器初始化价值,我们如何用英语证明和解释?

标签: javascript arrays ecmascript-6


【解决方案1】:

reducer 在数组的每个元素上执行,但“数组的每个元素”只是一个参数,为什么我可以假设 SUM 是另一个参数并缓存在某个地方等待下一次添加操作?

提供的回调被多次调用,对数组中的每个项目调用一次(或者,对于length - 1 次,以防未提供初始值)。您可以自己轻松实现:

const array1 = [1, 2, 3, 4];
const reducer = (y, x) => y + x;

Array.prototype.myReduce = function(callback, initialValue) {
  let accum = initialValue === undefined
    ? this.shift()
    : initialValue;
  for (let i = 0; i < this.length; i++) {
    accum = callback(accum, this[i], i, this);
  }
  return accum;
}
// 1 + 2 + 3 + 4
console.log(array1.myReduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.myReduce(reducer, 5));

仅仅因为您将 一个 函数传递给 .reduce(或任何其他函数)并不会限制该函数可以被调用的次数。

为什么我可以假设 reduce 在最后返回总和?

这就是方法的定义方式——就像上面的实现一样,累加器(或accum)在每次迭代时都会重新分配,并传递给回调的下一次调用。

该方法的浏览器本机实现实际上并没有像上面那样用 Javascript 编写,但它的功能是相同的(大部分情况下)。

pipeline 的工作方式相同。对于提供的数组的每个元素,累加器都被重新分配,并使用新的累加器调用下一个元素。这里有一个函数数组被调用,每个函数的返回值都被用作下一个累加器,最后一个函数调用返回的值就是整个.reduce调用解析到的值。

const pipeline = [
  array => { array.pop(); return array; },
  array => array.reverse()
];

pipeline.reduce((xs, f) => f(xs), [1, 2, 3]);

第 1 项:初始值(累加器)为 [1, 2, 3]。插入array =&gt; { array.pop(); return array; } 和你.pop() 它的最后一个值(3,导致[1, 2],然后你返回数组。

第 2 项:累加器(最后一次迭代的返回值)是 [1, 2]。将其插入array =&gt; array.reverse(),您将得到相同的数组,相反:[2, 1]

数组中没有更多的项目,所以这个[2, 1] 是整个reduce 调用的值。

【讨论】:

  • 在第二个例子中,pipeline 是要归约的数组,(xs, f) => f(xs) 是归约函数,[1, 2, 3] 是累加器的初始值,我们如何用英语证明和解释这一点?
  • 它的工作方式相同 - 它遍历数组,执行与每个项目相关的操作,并返回一个值以用作下一个累加器。对于pipeline,该数组恰好是一个函数数组,每次调用的结果作为下一个累加器传递,直到结束,最终调用的结果是整个.reduce 解析为跨度>
  • 在第一个例子中,reducer 是 (y, x) => y + x;它适用于每个数组元素 [1, 2, 3, 4],这是有道理的。但在第二个例子中,reducer 是 (xs, f) => f(xs),它到底是什么?以及它如何作用于管道的每个数组元素?
  • (y, x) =&gt; y + x 将累加器添加到正在迭代的当前项,并返回总和。类似地,(xs, f) =&gt; f(xs) 使用累加器调用当前正在迭代的项,并返回结果。 .reduce 回调(此处为 f(xs) 函数调用)针对数组中的每个项目运行,如答案开头所述。
猜你喜欢
  • 2016-03-18
  • 2011-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多