跟 map/filter 这些数组方法不同,reduce 最大的特点就是给它一个数组,返回的内容可以是任意类型的值。reduce 也被称为万能数组方法,map/filter 能干的,reduce 也能干。

数组元素累加

一个最简单的 reduce 的使用情形。

let arr = [
  1, 3, 6, 9
]

const result = arr.reduce(
  (total, num) => {
    console.log(total, num)
    return total + num
  }
  , 0
)

console.log('result', result)

数组 arr 中的四个元素都是 number ,现在要求它们四个的和,就可以用 reduce 方法,reduce 方法要传入两个参数。

第一个参数是一个函数,因为 reduce 方法遵循函数式编程的思路,所以这里作为函数的这个参数,我们姑且叫它 reducer ,必须是一个纯函数,从参数中拿到输入,它负责的就是 return 回一个输出。

reducer 的第一个参数是一个用来存放最终运算结果的变量,有人叫它 accumulator 收集器,这里是 total ,中文意思是总和,reducer 的第二个参数是 num ,这个是迭代过程中拿到的数组的当前元素。

到 reducer 内部,先添加一个打印语句,监控每次迭代过程中 total 和 num 的变化,便于我们理解运行机制。最后, reducer 返回的是 total 加上 num 。reduce 函数,注意这次说的不是 reducer 了,的第二个参数,要传入的是 reducer 的第一个参数的初始值,这里显然应该传入零。所以,我们的推断是,total 的初始值就是这个零,然后下一次迭代,total 的值就是上一次的 total 加上 num ,也就是上一次 reducer 的 return 值。

终端中,执行 node index.js ,可以看到每次 total 和 num 打印的值,印证了之前的推断。

数组变成对象

redux 中常用的一种操作,就是把一个对象数组变成一个以数组中各个对象的 id 为属性名,对象本身为属性值的对象。

let products = [
  {
    id: '123',
    name: '苹果'
  },
  {
    id: '345',
    name: '橘子'
  }
]

const productsById = products.reduce(
  (obj, product ) => {
    obj[product.id] = product
    return obj
  },
  {}
)

console.log('result', productsById)

给出一个对象数组 products,每个对象代表一个商品,拥有 id 和 name 两个属性。

把最终转换的输出赋值给 productsById 常量,执行 reduce 方法,收集器是 obj ,当前值放到 product 参数中。

进入 reducer 函数内部,让 obj 中的以当前商品的 id 为属性名,对应的属性值为当前商品对象。然后返回 obj 对象。

reduce 函数的第二个参数是一个空对象,这个会作为 obj 的初始值。

命令行中,执行 node index.js 可以看到 productsById 转换成了一个咱们想要的对象了。