相信很多初学者都被javascript数组的reduce方法所困扰,对如何使用一头雾水。reduce方法是对数组的每个元素按顺序执行一个函数。该函数接收上一次执行的结果作为参数,并将结果传递给下一次调用。可以很好地使用reduce方法来简化复杂的逻辑,提高代码的可读性。下面的例子可以帮助你快速了解reduce的用法。1.数数组求和这是reduce最常见的入门级例子。如果像这样使用传统的for循环:functionsum(arr){letsum=0;for(constvalofarr){sum+=val;}returnsum;}sum([1,3,5,7]);//16如果你使用reduce():functionsum(arr){construducer=(sum,val)=>sum+val;constinitialValue=0;returnarr.reduce(reducer,initialValue);}sum([1,3,5,7]);//16reduce()函数的第一个参数是reducer函数,第二个参数是初始值。对每个数组元素执行reducer函数,第一个参数是“递增值”。渐进值的初始值为initialValue,每轮调用后更新为reducer函数的返回值。为了帮助理解,可以使用for循环实现一个简单的reduce()函数:functionreduce(arr,reducer,initialValue){letaccumulator=initialValue;for(constvalofarray){accumulator=reducer(accumulator,val);}returnaccumulator;}2.一个对象数组的数值属性值之和单看reduce()本身,大家更多的是觉得它的晦涩难懂,而不是它的易用性。如果只是对一个数组求和,使用for循环可能更直观。但是,当你将它与其他数组方法(如filter和map)结合使用时,你就能感受到它的强大和便利。例如,假设有一个对象数组,每个对象都有一个total属性。对这些总数求和:constlineItems=[{description:'Eggs(Dozen)',quantity:1,price:3,total:3},{description:'Cheese',quantity:0.5,price:5,total:2.5},{描述:'黄油',数量:2,价格:6,总数:12}];使用reduce这样写:lineItems.reduce((sum,li)=>sum+li.total,0);//17.5这样可以得到最终的结果,但是代码的可组合性不太好.你可以做一些优化来提前提取总属性:lineItems.map(li=>li.total).reduce((sum,val)=>sum+val,0);为什么第二种方式更好?因为这样可以将求和的逻辑抽象成一个单独的函数sum(),方便后面复用。//汇总totallineItems.map(li=>li.total).reduce(sumReducer,0);//汇总数量lineItems.map(li=>li.quantity).reduce(sumReducer,0);functionsumReducer(sum,val){returnsum+val;}这种抽象比较重要,因为你认为sumReducer()的逻辑不会变,其实并没有。例如,这个求和逻辑没有考虑到0.1+0.2!==0.3的问题。(参考为什么0.1+0.2=0.300000004)有了这个抽象,修复这个缺陷就更方便了。例如:const{round}=require('lodash');functionsumReducer(sum,val){//保留2位小数return_.round(sum+val,2);}3.求最大值reduce()为通常使用Summing,但它的作用远不止于此。累加器可以是任何值:数字、空值、未定义、数组、对象等。例如,假设有一个日期数组,要找到最新的日期:constdates=['2019/06/01','2018/06/01','2020/09/01',//这是最新的日期,但如何找到它?'2018/09/01'].map(v=>newDate(v));一种方法是对数组进行排序并找到最后一个值。好像可以,但是效率没有那么高,而且用数组默认的方法对日期对象进行排序其实有点问题。不只是日期对象,在sort()方法中比较的任何类型的值都会默认转换为字符串比较,最终的结果可能不是你想要的。consta=[4,1,13,2];//你是惊讶还是意外?a.sort();//[1,13,2,4]这里可以用reduce()处理://这里是用`>`和`<`来比较日期对象,所以不会有问题constmaxDate=dates.reduce((max,d)=>d>max?d:max,dates[0]);4.分组计数假设有一个对象数组,每个对象都有一个age属性:constcharacters=[{name:'Tom',age:59},{name:'Jack',age:29},{name:'布鲁斯',年龄:29}];如何返回包含每个年龄的字符数的对象?例如:{29:2,59:1}。reduce()的实现如下:constreducer=(map,val)=>{map[val]=map[val]||1;++map[val];returnmap;};characters.map(char=>char.age).reduce(reducer,{});5.Promise动态链式调用假设你有一个异步函数数组,想要按顺序执行它们:constfunctions=[asyncfunction(){return1;},asyncfunction(){return2;},asyncfunction(){return3;}];如果它是一个静态的Promise代码,我们可以直接在代码中链接它。但是如果是动态的Promise数组,可以使用reduce串起来://`res`的最终结果相当于`Promise.resolve().then(fn1).then(fn2).then(fn3)`constres=awaitfunctions.reduce((promise,fn)=>promise.then(fn),Promise.resolve());res;//3当然reduce可以做的事情有很多,它本质上是执行一些一种最终返回单个值的“渐进式”操作。本文转载自微信公众号“1024翻译站”,可通过以下二维码关注。转载请联系1024翻译站公众号。
