reduce 定义
reduce 在 MDN 里面的定义如下
看起来有点绕,不过从代码上来看就好理解多了
|
|
reduce 接受两个参数,一个回调函数,一个初始值上文中的 (acc,val)=>acc+val
就是回调函数,0
则是遍历的初始值
其中在回调函数中,会传入四个参数
- accumulator 上一次调用回调返回的值,或者是提供的初始值(initialValue)
- currentValue 数组中正在处理的元素
- currentIndex 数据中正在处理的元素索引,如果提供了 initialValue ,从0开始;否则从1开始
- array 调用 reduce 的数组
最终返回累计处理的结果
为何 reduce
与 forEach 相比起来,reduce 不同之处在于,回调的首参不是列表中的元素,而是上一个调用的结果,或者是我们提供的初始值。
至于为什么……
如果说 forEach 是对应最基础的一种循环调用
|
|
reduce 则对应另外一种我们更经常会写的,带有累加概念的循环
|
|
而事实上第二种循环我们使用的频率也十分的高,但是当我们想用 forEach 抽象第二个循环的时候就会遇到一个麻烦。
因为这个循环体内的逻辑是不独立的,我们实际上借助了一个外部变量保持循环的结果,在循环之间传递数据。
对于每个循环逻辑独立,最后也不返回数据的 forEach 调用,我们无法抽离出一个独立的函数。
因此,reduce 就是为了解决了这个问题,将需要保持一个外部变量的逻辑,抽像为每次循环中上次执行的结果,传入到遍历函数当中,求得累加的结果,很有点递归的意味。
有趣的 reduce
而实际上这样一个遍历的逻辑,即便我这样解释列一大段,看起来还是稍显怪异,不禁让人想问那么到底有什么实际用途呢。
这确实有些不好解释,因为这是一个高度的抽像。
不过藉由 reduce 的抽象,我们可以定义出 map,filter 甚至是 compose 等等许多高级概念。
接下来我们就展示一下reduce的有趣之处!
map
定义 map, map 接受一个函数与数组,将函数应用到每个数组元素上,并返回一个将函数的结果作为新数组元素的数组
|
|
对于 map,我们通过对当前的 item 调用 fn ,并将结果 contact 到上一次调用返回的数组中,从空数组开始最终累积出新的数组
filter
同样的我们也可以通过 reduce 写出 filter,原理上来说与map的是实现非常相似,仅仅只是多加了一下判断而已
|
|
compose/flow
了解过 lodash 的人应该知道其中一个十分有用的函数 flow,他的作用在于接受一组函数,按顺序调用,且上一个函数的结果就是下一个函数的参数。
这样看起来是不是熟悉?
|
|
总结
希望这篇文章能让你开始感受到 reduce 的有趣之处,虽然比起 map 或者 forEach 等等概念上来说,理解起来没那么容易。
但这是一个非常有用的工具,可以衍生出许多有趣的东西,绝对值得你花一点时间去去了解。