美文网首页
JS Array.reduce 理解与使用

JS Array.reduce 理解与使用

作者: 夹板儿孩 | 来源:发表于2021-03-27 01:38 被阅读0次

    这个 reduce 函数,说起来其实也挺简单的,但是要实用起来有时候还是感觉有些困难
    这是我自己的一些理解方式,分享给大家看一下,希望能帮助到不理解的小伙伴。直接用代码进行逐步的讲解
    可能会比较啰(话)嗦(多),但是你看完了,应该就会用了

    急性子可以直接去看 更多例子下的二维数组合并 看完应该也能理解
    急性子可以直接去看 更多例子下的二维数组合并 看完应该也能理解

    我们先来看看主角 reduce 都有哪些参数 【这段内容相对比较重要】
    Array.reduce( Function, initValue )
    两个参数都非常的重要(虽然第二个可有可无)
    Function: 不用说,肯定是个回调函数。由开发者提供 reduce 来回调
    initValue: 第一次回调 Function 时会将 initValue 传入到 Function 的第一个参数中

    ps: 插入一段内容,我发现有的博主没有说。就是当 initValue 没有传入的时候,Function 的第一个参数,将会是数组 0 所对应的值届时 reduce 也将会少走一次循环


    接下来说一下 Function 回调时 reduce 都给了哪些参数
    function(pre, cur, index, arr)
    pre: 上一次的结果集,这个值通常会使用 initValue 作为第一次的默认参数,不过,我上面也有提到,当 initValue 没有传入参数时这个值将会是 数组 的第一个值
    cur: 当前元素,与我们使用 forEach/map 时的 item 一样。都是当前循环到的那个对象
    通常我们只会使用上面的两个属性
    index: 当前元素的索引
    arr: 当前元素所属的数组

    看完了上面对 reduce 之后,应该就会对 reduce 有一个模糊的了解了,接下来看看它与平常使用方式区别

    //跟其他博主一样,我们也用要给简单的数组开始讲
    //需求:我们现在有如下这么一个数组,我们想要获得这个数组的总和
    let arr = [1,2,3,4,5];
    

    方式一

    传统方式,使用一个循环来循环累加,
    下面代码是对传统方式的一种例子
    这种方式完全可以实现,并且代码量其实也并不复杂。但是我们既然要学习新的高阶函数,那么我们就不在推荐大家使用这种方式了,接下来请看【二】
    ps:大家既然都来学 reduce 了,我就默认大家都会使用 => 箭头函数了,这里不对箭头函数做专门的讲解了

    let count = 0;
    arr.forEach(item=>count+=item);
    console.log(count); //15
    

    这方式一实在是太简单了吧。。。我就不讲了

    方式二

    使用 reduce 函数
    如下代码:

    let count = arr.reduce(function(pre, cur){
        return pre+cur
    });
    console.log(count); //15
    

    看到这里,你可能会有疑问,这代码量丝毫不比传统方式少,但是为什么还要用这种方式
    如果你有这种疑问,那你可能就对 箭头函数 还不够理解,接下来我就要变形了!

    上面都说了不讲 箭头函数 了,但是我这里还是想用用 function 因为直接用 箭头函数 会变得比较难以理解,上面的那个代码纯粹是为了给初学者带来更好理解的一种方式。希望大家把这两种方式都牢记,能够在心里进行转换

    方式二变形

    let count = arr.reduce((pre,cur)=>pre+cur)
    

    二维数组合并

    //需求:将如下二维数组进行合并处理
    let arr2 = [[1,2,3], [4,5,6], [7,8,9]]
    

    插播一则小广告:我这里有一个我自己封装的多维数组拍平也是使用的 reduce 感兴趣的小伙伴可以来瞅瞅 点我查看 看完下面的代码,相信你也能写出来。好了,继续

    let newArray1 = arr2.reduce(function(pre,cur){
        return pre.concat(cur);
    }, []);
    let newArray2 = arr2.reduce((pre,cur)=>pre.concat(cur), []);
    console.log(newArray2); //[1,2,3,4,5,6,7,8,9]
    

    讲解一下代码执行原理
    reduce 第一次进入循环时,会将我们的第二个参数传入到 pre 中
    ----此时 pre = [], cur = [1,2,3];
    ----然后我们将 pre 与 cur 使用 concat 拼接成了一个新的数组,并 return
    reduce 第二次进入循环
    ----此时 pre = [1,2,3], cur = [4,5,6]
    ----然后我们再次将 pre 与 cur 使用 concat 拼接成了一个新的数组,并 return
    reduce 第三次进入循环(由于 arr2 长度也就 3 所以这也是最后一次)
    ----此时 pre=[1,2,3,4,5,6], cur=[7,8,9]
    ----然后我们再次将 pre 与 cur 使用 concat 拼接成了一个新的数组,并 return
    reduce 退出循环 并将 pre 抛出
    我们将会得到最后的结果 [1,2,3,4,5,6,7,8,9]

    附文:

    我们上面有提到过,当我们的 initValue 不传入时,reduce 会将数组第一位作为初始值,并且我们事先知道我们需求中,二维数组是固定的两层数组 如:表格 那么我们这时就可以省掉 reduce 的第二个 initValue 参数(虽然节约不了太多的性能)

    当我们去掉 initValue 参数时,我们得到的结果是这样的
    reduce 第一次进入循环
    ----此时 pre = [1,2,3], cur = [4,5,6]
    ----然后我们将 pre 与 cur 使用 concat 拼接成了一个新的数组,并 return
    reduce 第二次进入循环(我们这里其实循环就不再从 0 开始了,而是从 1 开始,所以这也是最后一次循环)
    ----此时 pre=[1,2,3,4,5,6], cur=[7,8,9]
    ----然后我们再次将 pre 与 cur 使用 concat 拼接成了一个新的数组,并 return
    reduce 退出循环 并将 pre 抛出
    我们将会得到最后的结果 [1,2,3,4,5,6,7,8,9]

    五个例子

    //需求1,对下面数组进行去重处理
    //需求2,找到下面数组中的最大数和最小数
    //需求3,得到下面数字每次出现的次数
    let arr = [1,2,3,1,2,3,4,5,6];
    //需求4,对如下数组,根据 name 进行去重处理
    let arr2 = [
        {name: '小杜'},
        {name: '小杜'},
        {name: '李四'},
        {name: '王五'},
        {name: '王五'},
        {name: '小青'},
        {name: '小青'},
        {name: '桃子'},
        {name: '小刘'}
    ];
    //需求5,对如下数组根据姓名首字母分类,得到 arr3_result 例子结果
    let arr3 = [
        { name: 'Bob' },
        { name: 'Ben' },
        { name: 'Cole' }, 
        { name: 'Mary' }, 
        { name: 'Travis' }
    ]
    let arr3_result = {
        B: ['Bob', 'Ben'],
        C: ['Cole'],
        M: ['Mary'],
        T: ['Travis']
    }
    
    //需求1,对数组进行去重处理
    let arr_result = arr.reduce((pre, cur) => {
        !!!pre.includes(cur) && pre.push(cur);
        return pre;
    }, []);
    console.log(arr_result); //[1,2,3,4,5,6]
    
    
    //需求2,找到数组中的最大数和最小数
    console.log("最大数", arr.reduce((pre, cur) => pre > cur ? pre : cur))     //6
    console.log("最小数", arr.reduce((pre, cur) => pre < cur ? pre : cur))     //1
    
    //需求3, 得到各数字每次出现的次数
    console.log("各出现次数结果", arr.reduce((pre, cur) => {
        let val = pre[cur] || 0
        pre[cur] = ++val
        return pre
    }, {}))
    
    //需求4,根据 name 进行去重处理
    let arr2_result = arr2.reduce((pre, cur, index) => {
        if (!pre.names.includes(cur.name)) {
            pre.names.push(cur.name)
            pre.unique.push(cur)
        }
        if(index === arr2.length-1){
            return pre.unique   //最后一次循环时,将唯一的数组丢出
        }else{
            return pre
        }
    }, {unique: [], names: []});    //传入两个对象,unique保存名字唯一的对象, names保存唯一的名字
    console.log(arr2_result);
    //[{name:'小猴'},{name:'小玉'},{name:'桃子'},{name:'小刘'}]
    
    //需求5,对数组 arr3 进行根据姓名首字母分类,得到 arr3_result 例子结果
    let tt = arr.reduce(function (pre, cur) {
        let name = cur.name     // 2.从当前的对象中取出 name 的值
        let letter = name[0]    // 3.从 name 中取出首字母
    
        let names = pre[letter] // 4.将 letter 从对象中取出
        if(names === undefined) names = []  // 4.1 pre 中是否已经存在 letter 的数组,如果没有,则新建一个数组
    
        names.push(name)        // 5.将姓名放到 letter 对应的数组中
        pre[letter] = names     // 6.重写 pre letter对应的数组
    
        return pre  // 7.将 pre 丢出作为下一次循环的默认值
        // 1.传递一个空对象给 reduce 作为默认值
    }, {})
    console.log(tt)
    

    更多例子

    下面我们举一些其他的例子来讲解

    数组求和与数组求平均值

    数组与树形相互转换

    实现一个我们自己的 reduce

    现在,通过我们对上述代码学习后,应该有一点初步的了解了,下面我们对 reduce 进行深入的研究,实现一个我们自定义的 reduce

    // 例子
    function Array2(arr) {
        this.arr = arr
        this.reduce = function (func, arg) {
            let index = arg === undefined ? 1 : 0   //获得循环起始位置,当没有传默认值时,从 1 开始循环
            let pre = arg || this.arr[index]        //当给了默认值,则首次使用默认值,否则使用数组 0 的值作为上一次的值
            for (let i = index; i < this.arr.length; i++) {
                //获得回调结果,将结果作为最后最后一次值
                pre = func(pre, this.arr[i], i, this.arr) // 回调的四个参数:上一次结果,当前值,当前索引,当前数组
            }
            return pre //将结果抛出
        }
    }
    
    // 使用
    let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, 9, 3, 2, 5, 6, 23, 47, 5, 3, 4, 6, 7, 2, 0, -2, -20, -66]
    console.log("去重结果", new Array2(arr)
        .reduce((pre, cur) => {
            !pre.includes(cur) && pre.push(cur)
            return pre
        }, [])
    )
    

    相关文章

      网友评论

          本文标题:JS Array.reduce 理解与使用

          本文链接:https://www.haomeiwen.com/subject/uzashltx.html