当前位置: 首页 > 科技观察

JS数组Reduce的妙用,收藏等于学习!

时间:2023-03-12 04:43:39 科技观察

本文转载自微信公众号《前端发现》,作者为前端发现者。转载本文请联系前端发现公众号。说到处理数组的方法,想必大家都不陌生。今天,我们就来学习一下常见场景下处理数组的方法。首先我们看一下reduce方法函数可以传入哪些参数(pre,cur,index,arr)pre:需要,初始值或者计算后的返回值cur:不需要,当前处理的元素index:不需要,当前处理的元素的索引arr:不需要,当前元素所属的数组对象直接看constlist=[1,2,3,4,5]constresult=list.reduce(function(pre,cur,index,arr){console.log('pre:'+pre,'cur:'+cur,'index:'+index)returnpre+cur})console.log(result)//=>pre:1cur:2index:1//=>pre:3cur:3index:2//=>pre:6cur:4index:3//=>pre:10cur:5index:4//=>15可以看到第一轮的值ofpre是数组的第一个值,那么当前处理的元素直接是该元素的第二个数据,索引为数组的1。第二轮pre是第一次逻辑处理返回pre+cur(即3)的结果。以此类推……一共4轮。我们来看一个乘法处理逻辑:constlist=[1,2,3,4,5]constresult=list.reduce(function(pre,cur,index,arr){console.log('pre:'+pre,'cur:'+cur,'index:'+index)returnpre*cur})console.log(result)//=>pre:1cur:2index:1//=>pre:2cur:3index:2//=>pre:6cur:4index:3//=>pre:24cur:5index:4//=>120看起来好复杂,能举个简单的例子吗?不问,只问!constresult=列表。reduce((pre,cur)=>pre+cur)console.log(result)//=>15很简单,再试试高级的。数组去重在传递数组之前,我们先了解一下reduce的另一个方面,即initialValue。它表示传递给函数的初始值,“可以理解为给pre设置一个默认值”。constlist=[1,1,3,5,5,7,9]letarr=list.reduce((pre,cur)=>{if(!pre.includes(cur)){returnpre.concat(cur)}else{returnpre}},[])//=>为pre[]设置默认空数组console.log(arr)//=>[1,3,5,7,9]可以看到长度list数组为7,共循环7次(设置默认空数组,导致cur的第一轮是数组的第一个数据)。每循环一次,判断pre数组中是否有当前循环的元素,如果不存在则加入pre数组,否则直接退出当前循环。二维转一维数组letarr=[1,2,[4,6],[1,6],[2,2]]letnewArr=arr.reduce((pre,cur)=>{returnpre.concat(cur)},[])console.log(newArr)//=>[1,2,4,6,1,6,2,2]这里其实是用了数组的concat方法,类似于上面的用法,理顺一下就可以理解了。数组多维转一维letarr=[1,2,[4,6],[1,6,[3,6]],[1,[3,4,[1,2]],[2,2]]]constnewArr=(arr)=>{returnarr.reduce((pre,cur)=>{returnpre.concat(Array.isArray(cur)?newArr(cur):cur)},[])}控制台.log(newArr(arr))//=>[1,2,4,6,1,6,3,6,1,3,4,1,2,2,2]三目运算和concat数据拼接用到这里,递归的思想就完成了。先判断当前处理的元素(可能是数组)是否为数组(Array.isArray(cur)),如果是再执行newArr,否则直接处理当前元素,即把cur拼接成前面处理的大批。计算出现的元素个数在解释这个之前,让我们回顾一下for...in的用法:for...in语句用于循环/迭代数组或对象的属性。直接上vararr=['张三','李四','王舞']for(letxinarr){console.log(x)//=>张三//=>李四//=>王舞你可以看到,当arr是一个数组时,x等价于??for循环的标记。当arr是一个对象时呢?constobj={name:"张三",age:18,height:"180"}for(letkeyinobj){console.log(key)//=>name//=>age//=>height}可以看到当循环的“对象”是对象时,循环的单个项目是对象的属性。所以我们可以根据这个特征来判断一个对象是否是数组/对象的元素/属性。//判断下标时letarr=["a","b","2","3"]console.log("b"inarr)//=>falseconsole.log(2inarr)//=>true//对象letobj={a:"a",b:"b",c:"2",d:"3"时的判断属性}console.log("b"inobj)//=>trueconsole.log(2inobj)//=>false好了,回忆完这些知识,我们来看看如何完成这个需求letnames=['张三','李四','张三','王舞','王舞','王wu']lettotal=names.reduce((pre,cur)=>{if(curinpre){pre[cur]++console.log("判断为真:")console.log(pre)}else{pre[cur]=1console.log("判断为假:")console.log(pre)}returnpre},{})console.log(total);//=>{张三:2,李四:1,王五:3}首先传入一个{}对象,表示初始pre为{}。那么第一轮判断if,就变成了{}中的'张三'。显然,此时的判断条件为假。所以执行完else中的逻辑后,就变成了:{'张三':1}。第二轮的李斯也是如此。第三轮再次遇到“张三”时,此时的对象是{'张三':1,'李四':1},所以if判断为真,所以张三直接+1。我们看一下打印情况:判断为假//=>{张三:1}判断为假//=>{张三:1,李四:1}判断为真//=>{张三:1}:2,李四:1}判断为假//=>{张3:2,李四:1,王5:1}判断为真//=>{张3:2,李四:1,王五:2}判断为真//=>{张三:2,李四:1,王五:3}attributesumconstlist=[{name:'张三',age:18},{name:'李四',age:20},{name:'王舞',age:22}]lettotal=list.reduce((pre,cur)=>{console.log(cur)//=>{name:'张三',age:18}//=>{name:'李四',age:20}//=>{name:'王舞',age:22}returncur.age+pre},0)console.log(total)//=>60那么是否可以省去使用maptosum呢?写起来比较简单:lettotal=list.reduce((pre,cur)=>cur.age+pre,0)至此,今天的前端发现知识分享就结束了。