0


一个reduce还能玩出这么多花样儿?中高级前端都知道的reduce函数高级用法

reduce 函数是 JavaScript 中的一个功能强大的高阶函数,它算是 JS 数组方法里面较为复杂的一个函数了。reduce 的灵活性在于它能够遍历数组的所有元素,根据提供的函数累积一个最终的返回值。reduce()方法可以应用的场景特别多,循环遍历能做的,reduce都可以做,比如数组求和、数组求积、统计数组中元素出现的次数、数组去重等等。

一、reduce的用法

reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被作为初始值 initialValue,迭代器将从第二个元素开始执行(索引为 1 而不是 0)。

注意: reduce() 对于空数组是不会执行回调函数的。

语法如下:

array.reduce(function(total, currentValue, currentIndex, arr), initialValue
简洁语法:

reduce(callbackFn, initialValue)

function(total,currentValue, index,arr):回调函数,必需。

total:上一次回调函数的返回值,第一次调用回调函数时,如果指定的初始值 initialValue,那么该参数值就是 initialValue,否则就是数组元素的第一个。

currentValue:数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,那么当前处理的元素就是数组的第一个元素,否则的话就是第二个元素。

currentIndex:数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。

array:用于遍历的数组。

initialValue:可选。传递给函数的初始值。也就是第一次调用回调函数时参数total,是否指定初始值将会影响其它几个参数的值。

reduce 方法的返回值就是遍历所有数组执行回调函数后的返回值。

二、reduce的使用场景

2.1 数组求和

日常开发基本使用中,最简单其实就是数组求和的场景了。代码如下:

const arr =[1,2,3,4,5,6,7,8];const result = arr.reduce((total, currentValue)=>{return total + currentValue;},0);
console.log(result);// 36

按指定属性求和:

const arr =[{name:'张三',score:98},{name:'李四',score:86},{name:'王五',score:90},];const result = arr.reduce((total, currentValue)=>{return total + currentValue.score
},0);
console.log(result);// 274

按照条件求和:

const arr =[{name:'张三',score:93},{name:'李四',score:76},{name:'王五',score:80},{name:'赵六',score:65},];const result = arr.reduce((total, currentValue)=>{return currentValue.score >=80? total + currentValue.score : total;},0);
console.log(result);// 173

2.2 计算数组每个数据出现的次数

这种场景通常出现在算法题当中,借助 reduce 就可以简单实现它。其主要思路是通过键值对的形式巧妙的将出现的次数存储下来。

代码如下:

const arr =['Allice','Bob','Tiff','Bruce','Bob','Jack','Allice','Bob'];const result = arr.reduce((total, currentValue)=>{
    total[currentValue]=(total[currentValue]||0)+1;return total;},{});
console.log(result);// {Allice: 2, Bob: 3, Tiff: 1, Bruce: 1, Jack: 1}

变形:
同样的道理,也可以统计字符串中每个字符的出现次数,只需把字符串使用split方法分割成数组即可。

const str ='Hello World';const result = str.split('').reduce((total, currentValue)=>{
    total[currentValue]=(total[currentValue]||0)+1;return total;},{});
console.log(result);// {H: 1, e: 1, l: 3, o: 2, " ": 1, d: 1, r: 1, W: 1

2.3 数组去重

想不到吧!reduce还能实现数组去重?是的!

过程如下:

初始化一个空数组;

将需要去重处理的数组中的第1项在初始化数组中查找,如果找不到(空数组中肯定找不到),就将该项添加到初始化数组中;

将需要去重处理的数组中的第2项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中;

……;

将需要去重处理的数组中的第n项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中;

将这个初始化数组返回。

代码如下:

const arr =[1,2,2,3,3,4,4,5,6];const result = arr.reduce((total, currentValue)=>{if(!total.includes(currentValue)){
        total.push(currentValue)}return total;},[]);
console.log(result);// [1, 2, 3, 4, 5, 6]

2.4 数组扁平化

将初始值设置为了空数组,然后利用 concat 将数组中的每一项与初始值拼接,得到一个新的数组。

const arr =[['a','b'],['c','d'],['e','f']];const result = arr.reduce((total, currentValue)=>{return total.concat(currentValue);},[]);
console.log(result);// ['a', 'b', 'c', 'd', 'e', 'f']

2.5 将二维数组转为对象

又没想到吧!将二维数组转化为对象,其过程为将初始值设置为了空对象,currentValue可以看做为[key, value],然后total[key] = value把键值放入total对象中。

const arr =[['name','前端技术营'],['age','18'],['sex','男']];const result = arr.reduce((total,[key, value])=>{
    total[key]= value
    return total;},{});
console.log(result);// {name: '前端技术营', age: '18', sex: '男'}

2.6 提取数组中的特定值生产新数组

const arr =[{id:1,name:'Tom'},{id:2,name:'Jack'},{id:3,name:'Anna'}]const result = arr.reduce((total, currentValue)=>{return[...total, currentValue.name]},[]);
console.log(result);// ['Tom', 'Jack', 'Anna']

2.7 合并数组对象

const arr =[{name:'前端技术营'},{age:18},{sex:'男'}];const result = arr.reduce((total, currentValue)=>{return{...total,...currentValue }},{});
console.log(result);// {name: '前端技术营', age: 18, sex: '男'}

2.8 解析url参数

const url ='https://www.test.com/index.html?name=Jack&id=123456&latitude=31.101109&longitude=121.51367';const params = url.split('?')[1];const result = params.split('&').reduce((total, currentValue)=>{const[key, value]= currentValue.split('=');
    total[key]= value;return total;},{});
console.log(result);// {name: 'Jack', id: '123456', latitude: '31.101109', longitude: '121.51367'}

2.9 反序列化参数

conststringifyData=(data ={})=>{return Object.entries(data).reduce((total, currentValue)=>{return`${total}${currentValue[0]}=${encodeURIComponent(currentValue[1])}&`}, Object.keys(data).length ?"?":"").replace(/&$/,"");};const params =stringifyData({name:"Jack",id:'123456',age:18});const url =`https://www.test.com/index.html${params}`;
console.log(url);// https://www.test.com/index.html?name=Jack&id=123456&age=18

2.10 求最大值、最小值

计算数组中的最大值或最小值,可以使用原生api Math.max()和Math.min(),当然我们也可以使用reduce来实现。

const array =[1,10,6,8,3,9];const max = array.reduce((max, num)=>(max > num ? max : num));
console.log(max);// 10const min = array.reduce((min, num)=>(min < num ? min : num));
console.log(min);// 1

2.11 根据指定项分组

const arr =[{name:'小明',score:96},{name:'小华',score:88},{name:'小红',score:92},{name:'小刚',score:100},{name:'小李',score:96},{name:'小美',score:90},{name:'小芳',score:100},]const result = arr.reduce((total, currentValue)=>{const{ score }= currentValue;if(!total[score]) total[score]=[];
    total[score].push(currentValue)return total;},{})
console.log(result)

在这里插入图片描述

更复杂场景,多条件数据分类。

假设有一个包含人员信息的数组,每个人员对象有 age 和 gender 属性。现在我们想要根据人员的年龄和性别进行多条件分类。

const arr =[{name:'Alice',age:25,gender:'female'},{name:'Bob',age:30,gender:'male'},{name:'Charlie',age:25,gender:'male'},{name:'Dave',age:35,gender:'male'},{name:'Eve',age:25,gender:'female'},];const result = arr.reduce((accumulator, currentValue)=>{const{ age, gender }= person;if(!accumulator[age]){
        accumulator[age]={};}if(!accumulator[age][gender]){
        accumulator[age][gender]=[];}
    accumulator[age][gender].push(person);return accumulator;},{});

console.log(result);

在这里插入图片描述

2.12 管道函数

当结合其他高阶用法时,reduce 可以应用于非常复杂的场景。其中一个非常复杂的场景是实现函数组合或管道。管道(Pipe)是指输入一个值,依次经过管道(有序的函数运算)后输出这个值,也是函数编程的核心思想。

函数组合是一种将多个函数合并成一个新函数的技术,其中每个函数的输出都是下一个函数的输入。我们可以使用 reduce 和函数组合技术来实现函数管道,将一系列函数应用于数据并依次传递结果。

functionadd10(num){return num +10;};functionmultipl2(num){return num *2;};functiondivide3(num){return num /3;};constcompose=(fns)=>(initialValue)=> fns.reduce((previous, current)=>current(previous), initialValue);const calculate1 =compose([add10, divide3]);const calculate2 =compose([divide3, add10, multipl2]);// 先加10,在除以3
console.log(calculate1(20));//10// 先加10,在除以3,最后乘以2
console.log(calculate2(9));//26

三、总结

reduce 是数组的归并方法,与forEach、map、filter等迭代方法一样都会对数组每一项进行遍历,但是reduce可同时将前面数组项遍历产生的结果与当前遍历项进行运算,这一点是其它迭代方法无法企及的。

reduce除了以上介绍的使用场景外,还有很多其它使用场景,有兴趣的朋友可以研究一下。

标签: 前端

本文转载自: https://blog.csdn.net/qq_39327418/article/details/139938026
版权归原作者 前端技术营 所有, 如有侵权,请联系我们删除。

“一个reduce还能玩出这么多花样儿?中高级前端都知道的reduce函数高级用法”的评论:

还没有评论