为什么说数组实例的 reduce 方法灵活?

简介: 前端西瓜哥

我们在业务开发中,经常要处理数组,转换为我们需要的数据。所以我们会经常使用数组实例方法,常用到的有 forEach、map、filter 等,它们符合单一职责原则,简单易懂,适合初学者。

而 reduce 方法,就没这么好理解了,但是它更加灵活,适合老鸟写一些花里胡哨的代码。

今天西瓜哥我就聊聊 reduce。

1


 

reduce 是什么?

Array.prototype.reduce 的用法是:迭代执行回调函数,并将回调函数返回的值传入给下一轮迭代。取最后一个迭代返回的值,作为 reduce 的返回值。

reduce 这个词又该如何理解?reduce 最常见的意思是 “减少”。根据用法,可能更适合翻译为 “折叠”。reduce 方法将每次迭代产生的结果带到下一次迭代中,最后将二维的线(数组)折叠为一维的点。虽然这个返回值可能也是数组,但从返回值这个维度,还是算作点。

继续详细讲解 reduce 的用法。

reduce 接收两个参数。

第一个参数是回调函数 reducer。

reducer 回调函数会接受由 reduce 提供的 4 个参数:

  1. accumulator:累加器,为上一个迭代执行的回调函数的返回值呀
  2. currentValue:当前迭代的数组元素的值
  3. index:当前迭代的数组元素的索引
  4. array:源数组

reducer 返回的值会在下一次迭代中传入到回调函数中。

第二个参数是初始值,是可选的。

如果不提供初始值,reduce 会将首元素作为累加器初始值,并从第二个数组元素开始迭代。

如果提供初始值,reduce 会将其作为累加器初始值,并从首数组元素开始迭代。

需要注意的是,数组为空的情况下,不提供初始值,会报类型错误。建议尽量提供初始值,以应对空数组的特殊情况。



Uncaught TypeError: Reduce of empty array with no initial value


2


 

reduce 的简单实现

要想真正理解这个神奇的 reduce 的运行机制,还得自己实现一下。这里我实现个简单的 reduce 方法:

Array.prototype.myReduce = function(callbackFn, initVal) {  const arr = this;  if (typeof callbackFn !== 'function') {    throw new TypeError(callbackFn + ' is not a function');  }  let i = 0;  let acc = initVal;  if (arguments.length < 2) { // 没有提供初始值的情况    if (arr.length === 0) {      throw new TypeError('Reduce of empty array with no initial value');    }    acc = arr[0];    i = 1;  }
  for (; i < arr.length; i++) {    acc = callbackFn(acc, arr[i], i, arr);  }  return acc;}


核心代码在于通过 arguments.length 判断是否有提供第二个参数(默认值参数)。

如果提供了,累加器变量设置为传入的默认值,迭代从索引 0 开始(i = 0);如果没有提供,累加器变量设置为首个数组元素,迭代从 1 开始。

不要用第二个参数是否为 undefind 来判断,因为 undefind 也是可以作为默认值传入的。

3  

reduce 的一些用法

reduce 最常见的用法是对数组求和,写法如下:


const arr = [1, 2, 3];const sum = arr.reduce((sum, cur) => sum + cur, 0); // 6


为了兼容空数组的情况,建议加上初始值 0。

在 ES5 时代,reduce 还能做下面的事情:

  1. 拍平二维数组,现在用 Array.prototype.flat
  2. 数组去重,现在用 Array.from(new Set(arr))
  3. ...

其实说起来这些实现,forEach 也能实现。比如求和。


const arr = [1, 2, 3];let sum = 0;arr.forEach(val => { sum += cur });


但是 reduce 优点是不需要在方法外部声明一个变量,要更优雅一些。

而且如果 sum 变量名要修改了,reduce 函数里也不需要跟着改。

4

reduce 为什么灵活?

说 reduce 灵活,是因为它返回的值可以不是数组,可以是任何类型。比如我们你想要将数组通过特定规则转换为对象,reduce 就非常合适。

这代表了 reduce 是一个能灵活返回任意类型值的迭代器

它能实现 forEach、map、filter、find 这些功能单一的方法,当然这没必要,但它确实可以。

相关文章
|
6月前
|
分布式计算 负载均衡 数据处理
MapReduce中的Combiner函数的作用和使用场景
MapReduce中的Combiner函数的作用和使用场景
291 0
|
1月前
|
缓存 监控 JavaScript
|
13天前
|
存储
`map()`方法在什么场景下会比 `forEach()`方法更高效?
综上所述,当需要对数组元素进行复杂的转换并生成新数组、进行链式调用和函数式编程、处理元素之间存在明确映射关系的情况以及与其他数组方法结合使用时,`map()`方法比`forEach()`方法更高效,能够使代码更加简洁、清晰和易于维护。
51 32
|
5月前
|
Java 容器
2分钟学习ThreadLocal的Lambda构造方式
2分钟学习ThreadLocal的Lambda构造方式
24 0
|
6月前
|
存储 安全 C语言
C++中灵活 处理可变参数的多种方式:优缺点、应用场景及示例对比
C++中灵活 处理可变参数的多种方式:优缺点、应用场景及示例对比
137 1
|
6月前
|
分布式计算
MapReduce中的Map和Reduce函数分别是什么作用?
MapReduce中的Map和Reduce函数分别是什么作用?
360 0
|
SQL
在阿里云的E-MapReduce中,对数组类型进行聚合操作需要使用特定的函数
在阿里云的E-MapReduce中,对数组类型进行聚合操作需要使用特定的函数
52 2
|
11月前
动态参数+reduce累加stream
动态参数+reduce累加stream
48 0
|
监控 数据可视化 Serverless
函数计算常用的简化配置的方式
函数计算常用的简化配置的方式
760 2
|
JavaScript 索引
数组的扩展和新增方法
数组的扩展和新增方法
96 0
下一篇
无影云桌面