深刻理解全能的 Reducer

翻译: 刘小夕javascript

原文连接:css-tricks.com/understandi…css

更多文章可戳: github.com/YvetteLau/B…html

有一些小伙伴,对JavaScript的 reduce 方法还不够理解,咱们来看下面两段代码:java

const nums = [1, 2, 3];
let value = 0;

for (let i = 0; i < nums.length; i++) {
    value += nums[i];
}
复制代码
const nums = [1, 2, 3];
const value = nums.reduce((ac, next) => ac + next, 0);
复制代码

这两段代码在功能上是等价的,都是数组中全部数字的总和,可是它们之间有一些理念差别。让咱们先研究一下 reducer,由于它们功能强大,并且在编程中很重要。有成百上千篇关于 reducer 的文章,最后我会连接我喜欢的文章。git

reducer 是什么

要理解 reducer 的第一点也是最重要的一点是它永远返回一个值,这个值能够是数字、字符串、数组或对象,但它始终只能是一个。reducer 对于不少场景都很适用,可是它们对于将一种逻辑应用到一组值中并最终获得一个单一结果的状况特别适用。github

另外须要说明:reducer 本质上不会改变你的初始值;相反,它们会返回一些其余的东西。shell

让咱们回顾一下第一个例子,这样你就能够看到这里发生了什么,一块儿看一下下面的gif:编程

观看gif也许对咱们全部帮助,不过仍是要回归代码:数组

const nums = [1, 2, 3];
let value = 0;

for (let i = 0; i < nums.length; i++) {
    value += nums[i];
}
复制代码

数组 nums ([1,2,3]) ,数组中的每一个数字的第一个值将被添加到 value (0)。咱们遍历数组并将其每一项添加到 value函数

让咱们尝试一下不一样的方法来实现此功能:

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = function (acc, item) { 
    return acc + item;
}

const total = nums.reduce(reducer, initialValue);
复制代码

如今咱们有了相同的数组,但此次咱们不会改变初始值(即前段代码中的 value)。这里,咱们有一个仅在开始时使用的初始值。接下来,咱们能够建立一个函数,它接受一个累加器(acc)和一个项(item)。累加器是在上一次调用中返回的累积值(或者是 initialValue),是下一个回调的输入值。在这个例子中,你能够把它想象成一个滚下一座山的雪球,当它以每个吃过的值的大小增加时,它会吃掉它路径中的每一个值。

咱们将使用 .reduce() 来接收这个函数并从初始值开始。可使用箭头函数简写:

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = (acc, item) => { 
    return acc + item;
}

const total = nums.reduce(reducer, initialValue);
复制代码

进一步缩短代码长度,咱们知道箭头函数,在没有 {} 时,默认 return;

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = (acc, item) => acc + item;

const total = nums.reduce(reducer, initialValue);
复制代码

如今咱们能够在调用它的地方应用这个函数,也能够直接设置初始值,以下:

const nums = [1, 2, 3];

const total = nums.reduce((acc, item) => acc + item, 0);
复制代码

累加器多是一个使人生畏的术语,因此当咱们在回调调用上应用逻辑时,你能够将它想象成数组的当前状态。

调用栈

若是不清楚发生了什么,让咱们记录下每次迭代的状况。reduce 使用的回调函数将针对数组中的每一个项运行。下面的演示将有助于更清楚地说明这一点。我使用了一个不一样的数组([1,3,6]),由于数字与索引相同可能会使人困惑。

const nums = [1, 3, 6];

const reducer4 = function (acc, item) { 
    console.log(`Acc: ${acc}, Item: ${item}, Return value: ${acc + item}`);
    return acc + item;
}
const total4 = nums.reduce(reducer4, 0);
复制代码

当咱们执行这段代码时,咱们会在控制台看到如下输出:

Acc: 0, Item: 1, Return value: 1
Acc: 1, Item: 3, Return value: 4
Acc: 4, Item: 6, Return value: 10
复制代码

下面是一个更直观的分解:

  1. 累加器(acc)从初始值(initialValue):0 开始的
  2. 而后第一个 item是1,因此返回值是1(0+1=1)
  3. 1在下次调用时成为累加器
  4. 如今咱们累加器是1(acc),item (数组的第二项)是3
  5. 返回值变为4(1+3=4)
  6. 4在下次调用时成为累加器,调用时的下一项 item 是6
  7. 结果是10(4+6=10),是咱们的最终值,由于6是数组中的最后一项

简单示例

既然咱们已经掌握了这一点,那么让咱们来看看 reducer 能够作的一些常见和有用的事情。

咱们有多少个X?

假设您有一个数字数组,而且但愿返回一个报告这些数字在数组中出现的次数的对象。请注意,这一样适用于字符串。

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82];

const result = nums.reduce((tally, amt) => {
    tally[amt] ? tally[amt]++ : tally[amt] = 1;
    return tally;
}, {});

console.log(result);
//{ '1': 1, '3': 2, '4': 1, '5': 2, '6': 1, '82': 2 }

复制代码

最初,咱们有一个数组和将要放入其中的对象。在 reducer 中,咱们首先判断这个item是否存在于累加器中,若是是存在,加1。若是不存在,添加这一项并设置为1。最后,请返回每一项出现的次数。而后,咱们运行reduce函数,同时传递 reducer 和初始值。

获取一个数组并将其转换为显示某些条件的对象

假设咱们有一个数组,咱们但愿基于一组条件建立一个对象。reduce 在这里很是适用!如今,咱们但愿从数组中任意一个数字项建立一个对象,并同时显示该数字的奇数和偶数版本。

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82];

// we're going to make an object from an even and odd
// version of each instance of a number
const result = nums.reduce((acc, item) => {
  acc[item] = {
    odd: item % 2 ? item : item - 1,
    even: item % 2 ? item + 1 : item
  }
  return acc;
}, {});

console.log(result);
复制代码

控制台输出结果:

{ '1': { odd: 1, even: 2 },
  '3': { odd: 3, even: 4 },
  '4': { odd: 3, even: 4 },
  '5': { odd: 5, even: 6 },
  '6': { odd: 5, even: 6 },
  '82': { odd: 81, even: 82 } 
}
复制代码

当咱们遍历数组中的每一项时,咱们为偶数和奇数建立一个属性,而且基于一个带模数运算符的内联条件,咱们要么存储该数字,要么将其递增1。模算符很是适合这样作,由于它能够快速检查偶数或奇数 —— 若是它能够被2整除,它是偶数,若是不是,它是奇数。

其它资源

在顶部,我提到了其余一些便利的文章,这些文章有助于更熟悉 reducer 的做用。如下是个人最爱:

  1. MDN文档对此很是有用。说真的,这是他们最好的帖子之一,他们也更详细地描述了若是你不提供一个初始值会发生什么,咱们在这篇文章中没有提到。
  2. Coding Train
  3. A Drip of JavaScript

谢谢各位小伙伴愿意花费宝贵的时间阅读本文,若是本文给了您一点帮助或者是启发,请不要吝啬你的赞和Star,您的确定是我前进的最大动力。 github.com/YvetteLau/B…

关注公众号,加入技术交流群

相关文章
相关标签/搜索