reduce方法详解

549 阅读3分钟

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

引子

reduce方法非常灵活,对初学者而言,数组的reduce方法并没有那么容易理解,reduce能完成的事情for或者foreach也能完成,但是弄懂reduce方法之后,在别人的代码中遇见reduce,不至于有挫败的感觉。 大部分的数组方法,都返回一个新的数组,而reduce方法返回的值,却它可以返回任意类型的值,可以是数字、字符串,甚至可以是对象或新数组。从这里就能看出来它有多灵活。

简单理解

reduce方法会对数组元素逐一的执行回调函数,然后返回一个累积的值,用生活中的例子就是,做菜,购买了各种食材后,数组里的元素,就是油、盐、味精、青菜、香菇,最后把他们做成一道青菜香菇, 对他们分别的处理就是reducer函数。

语法:

arr.reduce(callback,[initialValue])
  • callback (执行数组中每个值的函数,包含四个参数)

    • previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
    • currentValue (数组中当前被处理的元素)
    • index (当前元素在数组中的索引)
    • array (调用 reduce 的数组)
  • initialValue (作为第一次调用 callback 的第一个参数。)

initialValue

当initialValue不存在时

当initialValue不存在时,当第一次循环时previousValue为数组的第一个元素,currentValue为数组的第二个元素,之后的循环previousValue为前一个循环的return返回值,currentValue为之后的元素,假设数组总共有n个元素,只会循环n+1次。

当存在initialValue时

当initialValue存在时,在第一次循环时previousValue为initialValue的值,currentValue为数组的第一个值,之后的循环previousValue为前一个循环的return返回值,currentValue为之后的元素,假设数组总共有n个元素,将会执行了n次循环。

reduce的应用

求和求积

function Accumulation(...vals) {
    return vals.reduce((t, v) => t + v, 0);
}

function Multiplication(...vals) {
    return vals.reduce((t, v) => t * v, 1);
}
Accumulation(1, 2, 3, 4, 5); // 15
Multiplication(1, 2, 3, 4, 5); // 120

权重求和

const scores = [
    { score: 90, subject: "chinese", weight: 0.5 },
    { score: 95, subject: "math", weight: 0.3 },
    { score: 85, subject: "english", weight: 0.2 }
];
const result = scores.reduce((t, v) => t + v.score * v.weight, 0); // 90.5

代替reverse

function Reverse(arr = []) {
    return arr.reduceRight((t, v) => (t.push(v), t), []);
}
Reverse([1, 2, 3, 4, 5]); // [5, 4, 3, 2, 1]

按属性对object分类

let people = [
 {name: 'Alice', age: 21},
 {name: 'James', age: 20},
 {name: 'John', age: 20}
];
const groupBy = (objectArray, property)=>{
 return objectArray.reduce((acc, cur)=>{
  let key = cur[property];
  if (!acc[key]) {
   acc[key] = [];
  }
  acc[key].push(cur);
  return acc;
 }, {})
};
let gruopedPeople = groupBy(people, ‘age’);
复制代码

代替map和filter

const arr = [0, 1, 2, 3];

// 代替map:[0, 2, 4, 6]
const a = arr.map(v => v * 2);
const b = arr.reduce((t, v) => [...t, v * 2], []);

// 代替filter:[2, 3]
const c = arr.filter(v => v > 1);
const d = arr.reduce((t, v) => v > 1 ? [...t, v] : t, []);

// 代替map和filter:[4, 6]
const e = arr.map(v => v * 2).filter(v => v > 2);
const f = arr.reduce((t, v) => v * 2 > 2 ? [...t, v * 2] : t, []);

数组降维

function Flat(arr = []) {
    return arr.reduce((t, v) => t.concat(Array.isArray(v) ? Flat(v) : v), [])
}
const arr = [0, 1, [2, 3], [4, 5, [6, 7]], [8, [9, 10, [11, 12]]]];
Flat(arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

总结

虽然reduce方法能完成的工作for或者foreach也能完成,但是高级函数reduce语义性更强,reduce函数理解的难度比其他数组方法稍微难点,但是稍微花点时间去学习,带来的收益还是挺高的。

参考文献

查缺补漏 女朋友问我能不能给她讲讲reduce 25个你不得不知道的数组reduce高级用法