查看原文
其他

让人欲罢不能的reduce(内含小编项目实战示例)

前端大全 2022-06-29

(给前端大全加星标,提升前端技能

转自:掘金 - 愤怒的黄牛

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一无所知的菜鸡,通过各方搜索资料,项目中的多方实践,只为让代表变得简洁方便。希望小编的这些总结能对各位工友们有一丢丢的帮助,也不枉小编把自己笔记本的总结分享出来了。


- EOF -


推荐阅读  点击标题可跳转

1、浏览器缓存

2、图解 Map、Reduce 和 Filter 数组方法

3、JavaScript两个快速调试的技巧


觉得本文对你有帮助?请分享给更多人

推荐关注「前端大全」,提升前端技能

点赞和在看就是最大的支持❤️

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存