让人欲罢不能的 reduce(内含小编项目实战示例)
(给程序员成长指北加星标,提升前端技能)
转自:掘金 - 愤怒的黄牛
https://juejin.cn/post/6921975823612248077
以前遇到复杂一点的数据结构处理时,for循环套for循环两梭子,代码篇幅大幅度增加,隔壁工位哥们看了不忍心了,说reduce那么好用为啥不用呢?菜鸡小编也不敢多问reduce怎么用,悄悄的下去查资料。而后分享给各位‘工友们’。
1. reduce到底是何方神圣
arr.reduce(callback,[initialValue])
reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
callback(执行arr中的每一个元素的函数,包含四个参数)
previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
currentValue (数组中的当前元素)
index (数组当前元素的索引)
array (调用reduce的当前数组)
initialValue (初始值)(可选参数)
!注意:如果没有写initialValue参数的话,reduce的callback会从arr的索引为1的元素开始执行,反之的话,会从索引为0的元素开始执行callback
2. reduce的简单到复杂
基本操作
let arr = [1,2,3]
const count = (arr) => {
return arr.reduce((pre,cur,index,array) => {
return pre + cur
},0)
}
count(arr) // 6
reduce造轮子--forEach
Array.prototype.myForEach = function (fn) {
return this.reduce((acc,cur,index,arr) => {
fn(cur,index)
})
}
arr.myForEach((item,index) => {
console.log(item,index)
})
利用原型挂载的原理,接受一个回调函数fn(就是myForEach的传入函数),利用reduce的原理调用传入的fn(),执行fn里面的一些数据操作。
reduce造轮子--map
const arr = [1,2,3]
const arr1 = [4,5]
Array.prototype.myMap = function(fn, thisArg) {
const result = [];
this.reduce((prev, curr, index, array) => {
result[index] = fn.call(thisArg, array[index], index, array);
}, 0)
return result;
}
arr.myMap(function(c,i) {
return c + i + this.length
},arr1)
// [3,5,7]
同理利用原型挂载的原理,传入map的函数,在原理的myMap函数的reduce函数中执行,利用第二个thisArg参数,再在reduce里面调用回调函数的时候call传入,改变myMap函数的this指向,将myMap函数的函数体执行结果,缓存在result数组中,返回出来。类似的filter,find,findIndex等思路都是一样的
reduce实践1-8
// p 为成员1,2,3,ps为成员的成绩,其中p和ps一一对应
// 求 每个成员的分数列表 {1: [1,2,2],2: [2,2,2], 3: [3,3,3]}
const p = [3, 3, 1, 2, 2, 1, 3, 2]
const ps = [69, 71, 93, 79, 81, 93, 77, 99]
const res = (p,ps) => {
return p.reduce((cur, pre, index) => {
if (!cur[pre]) {
cur[pre] = [];
}
for (let i = 0; i < ps.length; i++) {
if (index === i) {
cur[pre].push(ps[i]);
}
}
return cur
}, {})
};
console.log(res(p,ps));
// 按照年龄进行分组 {18: [],19: [], 20: []}
const arr = [
{name: '小孙', age: 18, score: 60, weight: 60},
{name: '小王', age: 19, score: 70, weight: 55},
{name: '小李', age: 18, score: 60, weight: 70},
{name: '小刘', age: 20, score: 70, weight: 65},
{name: '小赵', age: 18, score: 60, weight: 60},
{name: '小钱', age: 19, score: 70, weight: 55},
{name: '小周', age: 20, score: 60, weight: 50},
]
const groupBy = (arr, key) => {
return arr.reduce((pre,cur) => {
pre[cur[key]] = pre[cur[key]] || []
pre[cur[key]].push(cur)
return pre
}, {})
}
console.log(groupBy(arr, 'age'))
// 扁平化数组
const c = [[1,2,3],[4,5,[6,7]]]
const flatMap = (arr) => {
return arr.reduce((pre,item) => {
return pre.concat(Array.isArray(item) ? flatMap(item): item)
},[])
}
console.log(flatMap(c))
// 字符串大小写区别
const str = 'abCD'
const change = (str) => {
let arr = str.split('')
return arr.reduce((pre,cur) => {
if (cur === cur.toLowerCase()) {
pre.push(cur.toUpperCase())
} else {
pre.push(cur.toLowerCase())
}
return pre
},[])
}
console.log(change(str).join())
// 找数组中的公共元素
const arr10 = [1,2,3,4]
const arr2 = [6,4,7,8,3]
const arr3 = [0,9,4,3]
const getOnly = (...arr) => {
return arr.reduce((pre,next) => {
return pre.filter(c => next.includes(c))
},arr[0])
}
console.log(getOnly(arr10,arr2,arr3))
// 查找字符串中每个字符出现的次数
const str1 = 'jgdsgdlkgj'
const op = str1.split('').reduce((pre,next)=> {
pre[next]? pre[next]++: pre[next]=1
return pre
},{})
console.log(op)
// 查找公共前缀
const strArr = ["flower","flow","flight"]
const getStr = (strs) => {
return strs.reduce((pre,next) => {
while (!next.startsWith(pre)) {
pre = pre.substring(0,pre.length-1)
}
return pre
},strs[0])
}
console.log(getStr(strArr))
// 数组对象去重
const onlyList = (arr) => {
return arr.reduce((pre,cur,index) => {
if(pre.find(c => c.from === cur.from && c.to === cur.to)) {
return pre
} else {
return [...pre,cur]
}
}, [])
}
console.log(onlyList(quieArr))
结语
小编从一个reduce一无所知的菜鸡,通过各方搜索资料,项目中的多方实践,只为让代表变得简洁方便。希望小编的这些总结能对各位工友们有一丢丢的帮助,也不枉小编把自己笔记本的总结分享出来了。
1.看到这里了就点个在看支持下吧,你的「点赞,在看」是我创作的动力。
2.关注公众号
程序员成长指北
,回复「1」加入高级前端交流群!「在这里有好多 前端 开发者,会讨论 前端 Node 知识,互相学习」!3.也可添加微信【ikoala520】,一起成长。
“在看转发”是最大的支持