【译】10分钟学会reduce

原文连接:yazeedb.com/posts/learn…
原做者:Yazeed Bzadough前端

但愿这能够减小你的困惑

根据我学习和教学JavaScript的经验,reduce是最难掌握的概念之一。在这篇文章里,我将尝试解决一个核心问题...git

reduce 是什么,为何它叫 reduce程序员

reduce有不少名字

根据 Wikipedia, 其中一些包括github

  • Reduce
  • Fold
  • Accumulate
  • Aggregate
  • Compress

它们都暗示了核心思想。将结构分解为单个值编程

Reduce - 一个能够将列表折叠成任意数据类型的函数redux

这就像折叠一个盒子!使用reduce你能够将数组[1,2,3,4,5]每一项相加获得数字15数组

folding-box

新手方式

一般,你须要循环才能将列表”折叠“成数字函数式编程

const add = (x, y) => x + y;
const numbers = [1, 2, 3, 4, 5];
let total = 0;

for(let i = 0; i < numbers.length; i++) {
    total = add(total, numbers[i]);
}
console.log(total); // 15
复制代码

老司机方式

可是使用reduce你能够插入你的add函数,就能够为你处理循环了函数

const add = (x, y) => x + y;
const numbers = [1, 2, 3, 4, 5];

const total = numbers.reduce(add);
// 15
复制代码

你逐项地折叠1-5便可得到15工具

folding-box

三巨头

在深刻探讨以前,我认为先分析reduce和它著名的同伴-mapfilter很重要。它们严重掩盖了reduce的光辉,让它看起来很古怪。

creepy-reduce

尽管它们各自很受欢迎,但结合使用这三个巨人可让你随意操做列表!

the-big-three

这里咱们作个假设,伪装JavaScript不能使用循环,递归,或者像forEachsomefind等数组方法。只剩下mapfilterreduce三个方法。 可是咱们做为程序员的工做没有改变,咱们的应用程序中仍然须要三种类型的功能。

  1. 转换列表
  2. 筛选列表
  3. 将列表转换为其它数据类型(数字,字符串,布尔值,对象等)

让咱们看看咱们剩下的工具-map,filterreduce-如何应对这个挑战。

Array.map 转换列表

简而言之,将列表转换成其余列表是前端开发。所以map涵盖了你的大部分列表工做。

假设咱们的应用程序调用了一个用户列表的API,而且咱们须要在屏幕上显示每一个用户的用户名。只需建立一个返回用户用户名的函数。

const getUserName = (user) => user.name;
复制代码

而后插入map针对整个列表列表运行。

users.map(getUserName);
// ['Marie', 'Ken', 'Sara', 'Geoff', ...]
复制代码

Array.filter 判断列表

若是你想删除某些项而生成一个新列表,例如用户搜索他们的联系人列表?只需建立一个基于它的输入返回truefalse的函数。

const isEven = (x) => x % 2 === 0;
复制代码

而后插入filter针对整个列表运行。

const numbers = [1, 2, 3, 4, 5];
numbers.filter(isEven);
// [2, 4]
复制代码

Array.reduce 完成全部这些工做,甚至更多

mapfilter还不够时,你须要你们伙。map/filter能作的工做,reduce都能作,还有其余任何涉及遍历数组的。

reduce-will-take-this

例如,你将如何计算用户的总年龄?咱们的用户的年龄是25,22,29和30。

const users = [
  { name: 'Marie', age: 25 },
  { name: 'Ken', age: 22 },
  { name: 'Sara', age: 29 },
  { name: 'Geoff', age: 30 }
];
复制代码

mapfilter只能返回数组,可是咱们须要的是一个number

users.map(?);
users.filter(?);

// Nope! I need a number, not arrays.
复制代码

若是咱们有循环,咱们将遍历用户列表并经过一个计数器统计他们的年龄! 好吧,若是我告诉你使用reduce会更简单些?

users.reduce((total, currentUser) => total + currentUser.age, 0);
// 106
复制代码

fallout-hold-up

打印下log

我认为要理解它一个简单的方法就是每一步都用console.log打印出来

const users = [
  { name: 'Marie', age: 25 },
  { name: 'Ken', age: 22 },
  { name: 'Sara', age: 29 },
  { name: 'Geoff', age: 30 }
];

const reducer = (total, currentUser) => {
  console.log('current total:', total);
  console.log('currentUser:', currentUser);

  // just for spacing
  console.log('\n');

  return total + currentUser.age;
};

users.reduce(reducer, 0);
复制代码

这里有一张Chrome开发工具的截图。

reduce-screenshot-1

分解

如你所见,Array.reduce有两个参数

  1. reducer
  2. 初始值(可选)

reducer是完成全部工做的函数。当reduce循环遍历你的列表时,它提供两个参数给你的reducer

  1. 累加器
  2. 当前值

当前值不用说,就像你在常规循环中使用array[i]同样。不过,累加器是一个听起来很吓人的计算机科学术语,实际上很简单。

累加器是最终返回的值

当你循环遍历用户列表时,你如何跟踪它们的总年龄?你须要一些计数器变量来保存它。那就是累加器。它将做为最终值在reduce完成后输出。

在循环的每一步,它提供最后的累加器和当前值给你的reducer。不管reducer返回什么都将成为下一个累加器。当列表遍历完成而且你获得一个reduce后的单一的值, 循环结束。

reduce-screenshot-1

初始值是可选的

reduce的第二个参数初始值是可选的。若是不提供,默认为列表的第一个元素。

若是你要对纯数字求和,那很好。

[1, 2, 3].reduce((total, current) => total + current);
// 6
复制代码

可是若是你使用对象或数组会中断,由于你不该该将这些东西加起来。

[{ age: 1 }, { age: 2 }, { age: 3 }].reduce((total, obj) => total + obj.age, 0);

// 6
// Initial value fixes it.
// 0 + 1 + 2 + 3 = 6
复制代码

让咱们从新建立一个reduce

我不能理解我没法创造的东西-理查德·费曼(Richard Feynman)

但愿到目前为止,我已经对你有所帮助。如今是时候编写本身的reduce函数来真正锤炼本身了。

它将是一个有三个参数的函数。

  1. reducer
  2. 初始值
  3. 要操做的数组

对于这个demo,初始值不是可选的

const reduce = (reducer, initialValue, array) => {
  let accumulator = initialValue;

  for (let i = 0; i < array.length; i++) {
    const currentItem = array[i];
    accumulator = reducer(accumulator, currentItem);
  }

  return accumulator;
};
复制代码

仅需10行代码,6个关键步骤。我将一步一步说明。

  1. 定义reduce及其三个参数。
  2. 使用接收到的初始值参数初始化初始值(initialValue)。该变量每一个循环都将改变。
  3. 开始遍历数组。
  4. 捕获循环中数组的当前值(currentItem)。
  5. 调用reducer并将accumulatorcurrentItem传入,将结果做为新的accumulator保存。
  6. 当循环结束而且accumulator更改完成,将其返回。

多样的历史

我想谈谈更多关于 reducereducers 的历史,但不大肯定应该放在哪里。尽管如此,它仍是颇有趣的!

reducers是古老的

redux-did-not-invent-reducers

Redux为JavaScript开发人员带来了reducers的炫酷用法。但它没有发明他们。实际上不清楚是谁创造了该术语,但这里是我参考的一些参考文献。

递归理论(1952)

1952年出版的 这本书 从形而上学的角度讨论了reduce,将其称为fold。

Lisp程序员手册(1960)

1960出版的《Lisp程序员手册》中有一章是关于reduce函数的。

函数式编程概论(1988)

1988年出版的 这本书 谈论如何使用 reduce 将列表转换为其余值。 底线是一个古老的话题。你对计算机科学的研究越多,你就越意识到咱们正在从新包装几十年前发现的概念。

你对计算机科学的研究越多,你就越意识到咱们正在从新包装几十年前发现的概念。 — Yazeed Bzadough (@yazeedBee) October 13, 2019

为你准备的练习

为了节省时间,咱们就在这里结束。我但愿至少已暗示这reduce除求和以外的强大功能。

若是您有兴趣,请尝试这些练习(尽请关注后续文章)

  1. 使用 reduce 从新实现 Array.map 函数。
  2. 使用 reduce 从新实现 Array.filter 函数。
  3. 使用 reduce 从新实现 Array.some 函数。
  4. 使用 reduce 从新实现 Array.every 函数。
  5. 使用 reduce 从新实现 Array.find 函数。
  6. 使用 reduce 从新实现 Array.forEach 函数。
  7. 使用 reduce 将数组转换为对象。
  8. 使用 reduce 将二维数组转换为一维数组(flat)。

传送门

【译】使用reduce制做的10个JavaScript实用函数

相关文章
相关标签/搜索