JavaScript之reduce的高阶用法

很长的时间内,我一直以为数组的 reduce 用法,正如其名的含义一样,输出结果会 “reduce” 为一个值;以为 reduce 只能做些汇总求和之类的计算:

function sum(a, b) {
    return a + b;
}
const arr = [1, 2, 3, 4, 5];
arr.reduce(sum); // 15

对以上写法不熟悉数的朋友,可先看文章《javascript之高阶函数》

直到有天我得知原来 reduce 还有第二个可选参数;原来 reduce 不单能实现 filter or map 的功能,还能实现 filter and map 的功能!


用法: arr.reduce(callback[, initialValue]);

  • callback 为遍历数组时的回调函数。
    • callback有四个参数:callback(accumulator, currentValue[, currentIndex, array])
    • accumulator 为遍历时,上次 callback 的返回值;若有 initialValue 参数时,accumulator 的初始值为 initialValue;若无 initialValue 参数时,accumulator 初始值为数组的第一个元素。
    • currentValue 为 callback 遍历数组时的当前元素;若有 initialValue 参数时,currentValue 的初始值为数组的第一个元素;若无 initialValue 参数时,currentValue 初始值为数组的第二个元素。
  • initialValue 为指定 callback 初始遍历时 accumulator 的值。

下例,我们用 reduce 实现 filter + map 的功能:

// 找出 sex 为 female 的对象,并为其增加 weightMinusAge 字段
// weightMinusAge 为 身高 - 体重
const data = [
  {name: 'a', age: 37, weight: 72, sex: 'male'},
  {name: 'b', age: 17, weight: 64, sex: 'male'},
  {name: 'c', age: 24, weight: 89, sex: 'female'},
  {name: 'd', age: 66, weight: 83, sex: 'male'},
  {name: 'e', age: 47, weight: 105, sex: 'male'},
  {name: 'f', age: 18, weight: 61, sex: 'female'}
];

// accu 为 accumulator,curr 为 currentValue
const result = data.reduce((accu, curr) => {

  // if 判断,相当于 filter
  if (curr.sex === 'female') {

    // 为 currentValue 增加字段,相当于 map
    curr.weightMinusAge = curr.weight - curr.age;
    accu.push(curr);
  }
  return accu;
}, []);

console.log(result); 
// [
//  {name: "c", age: 24, weight: 89, sex: "female", weightMinusAge: 65}, 
//  {name: "f", age: 18, weight: 61, sex: "female", weightMinusAge: 43}
// ]



同理,开篇求汇总值的例子,也可为其添加汇总初始值:

function sum(a, b) {
    return a + b;
}
const arr = [1, 2, 3, 4, 5];
arr.reduce(sum, 10); // 25