Array.prototype.reduce 实用指南

hello~亲爱的看官老爷们你们好~最近由于工(lan)做(ai)繁(fa)忙(zuo),出产的文章多以译文为主,以前翻译了《如何在 JavaScript 中更好地使用数组》一文,发现很多同窗对 Array.prototype.reduce 不太熟悉,而我正好在这方面有一点积累,在此分享给你们。前端

Array.prototype.reduce 算是 JavaScript 数组中比较难用但又特别强大的方法,本文以实用为主,经过例子展现如何使用这个方法,但并不深挖这个方法的本质(深刻的话涉及到不少函数式编程相关的知识)~如下是正文。编程

Array.prototype.reduce 的简单介绍

reduce() 方法对累加器和数组中的每一个元素(从左到右)应用一个函数,将其简化为单个值。后端

上述是 MDN对该方法的描述,方法的语法是: arr.reduce(callback[, initialValue])callback 接受四个参数,分别是:accumulator,累加器累加回调的返回值; currentValue,数组中正在处理的元素;currentIndex(可选),数组中正在处理的当前元素的索引;array(可选),调用 reduce() 的数组。initialValue 为可选参数,做为第一次调用 callback 函数时的第一个参数的值。方法的返回值是函数累计处理的结果。数组

一股脑介绍完以后,估计很多同窗都是比较懵的。其实这个方法并不难理解的,正如它名字所示,抓住它的核心:聚合。通常而言,若是须要把数组转换成其余元素,如字符串、数字、对象甚至是一个新数组的时候,若其余数组方法不太适用时,就能够考虑 reduce 方法,不熟悉这个方法的同窗,尽管抛开上面的语法, 记住方法的核心是聚合便可。函数式编程

下文的例子都用到如下数组,假设经过接口获取到以下的数据体:函数

[{
  id: 1,
  type: 'A',
  total: 3
}, {
  id: 2,
  type: 'B',
  total: 5
}, {
  id: 3,
  type: 'E',
  total: 7
},...]
复制代码

数据体是按照 id 的升序进行排列,totaltype 不定~post

聚合为数字

根据上述数据体,咱们一块儿来作第一个小需求,统计 total 的总和。若是不用 reduce,其实也不难:spa

function sum(arr) {
  let sum = 0;
  for (let i = 0, len = arr.length; i < len; i++) {
    const { total } = arr[i];
    sum += total;
  }
  return sum;
}
复制代码

这个函数能够完成上述需求,但咱们精确地维护了数组索引,再精确地处理整个运算过程,是典型的命令式编程。上文说起,只要涉及将数组转换为另外的数据体,就可使用 reduce,它能够这样写:prototype

arr.reduce((sum, { total }) => {
  return sum + total;
}, 0)
复制代码

这样就完成了~sum 是此前累加的结果,它的初始值为 0。每次将此前的累计值加上当前项的 total 为这次回调函数的返回值,做为下次执行时 sum 的实参使用。看起来比较绕,能够参考下面的表格:翻译

轮次 sum total 返回值
1 0(初始值) 3 3
2 3 5 8
3 8 7 15
... ... ... ...

如此是否是清晰了不少?前一次的返回值就是后一次 sum 的值,如此类推,最后累积出总和,将数组聚合成了数字。

聚合为字符串

下一个需求是将数组的每项转换为固定格式的字符串(如第一项转换为 id:1,type:A;),每项直接以分号做为分隔。通常来讲,数组转为字符串,join 方法是不错的选择,但并不适用于须要精确控制或数组的项比较复杂的状况。在本例中,join 方法是达不到咱们想要的效果的。

使用 for 循环固然能够解决问题,但 reduce 也许是更好的选择,代码以下:

arr.reduce((str, { id, type }) => {
  return str + `id:${id},type:${type};`;
}, '')
复制代码

有了聚合为数字的例子,此次你能在脑海中模拟出执行的过程么?如下也是前三项的执行过程:

轮次 str id type 返回值
1 ''(初始值) 1 'A' 'id:1,type:A;'
2 'id:1,type:A;' 2 'B' 'id:1,type:A;id:2,type:B;'
3 'id:1,type:A;id:2,type:B;' 3 'E' 'id:1,type:A;id:2,type:B;id:3,type:E;'
... ... ... ... ...

聚合为对象

有了前面的一点基础,能够作复杂一点的聚合了。上面的数据体是比较典型的后端接口返回结果,但对于前端来讲,转换成 key value 的对象形式,更利于进行以后的操做。那咱们就以转换为 keyidvalue 是其余属性的对象做为目标吧!

function changeToObj(arr) {
  const res = {};
  arr.forEach(({ id, type, total }) => {
    res[id] = {
      type,
      total
    };
  })
  return res;
}
复制代码

如上所示,这个函数能够很好地完成咱们的目标。但略显啰嗦,记住:只要目标是将数组聚合为惟一的元素时,均可以考虑使用 reduce。这个例子刚好符合:

arr.reduce((res, { id, type, total }) => {
  res[id] = {
    type,
    total
  };
  return res;
}, {})
复制代码

res 是最后返回的对象,经过遍历数组,不断往里面添加新的属性与值,最后达到聚合成对象的目的,代码仍是至关简洁有力的。

最后,对于不熟悉这个方法的同窗,不妨练习一下,将数据体转换为一个字符串数组,数组每一项为原数组 type 的值。

小结

以上就是本文的所有内容,这里稍微小结一下 reduce 的优缺点~原则上说,只要是将数组聚合为惟一的元素时,均可以实现它。同时,它在函数式编程中有一席之地,也是声明式编程的典型例子。这也意味着它不容易掌握,若是熟悉 reduce 方法,写出来的代码可读性强,十分优雅。但在不熟悉的同窗眼里,这就是彻彻底底的天书了。如何更好地使用 reduce,避免写出难以维护的代码,值得每一位同窗思考。

感谢各位看官大人看到这里,知易行难,但愿本文对你有所帮助~谢谢!

相关文章
相关标签/搜索