js中数组reduce方法的使用和实现

作者: 绿芽 | 来源:发表于2022-08-01 12:52 被阅读0次

    js中数组reduce方法的使用和实现

    reduce方法定义

    reduce() 方法对数组中的每个元素执行一个传入的callback回调函数(升序执行,空值和已删除的除外),将其结果汇总为单个返回值。

    reduce方法语法

    arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

    reduce方法参数

    callback
    自己传入的为数组中每个值 (如果没有传入 initialValue则第一个值除外)执行的函数,包含四个参数:
    (1)accumulator
    累计器累计回调的返回值; 它是上一次调用callback回调时返回的值,或初始化时initialValue的值(见于下方)。

    (2)currentValue
    数组中当前正在处理的元素。
    (3)index 可选
    数组中当前正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。
    (4)selfArray可选
    调用reduce()的源数组自身。

    initialValue可选
    作为第一次调用 callback函数时的第一个参数的值。 如果没有传入初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

    reduce方法返回值

    函数累计处理的结果(可以是任意值,取决于自己需要什么)。

    reduce方法详细描述

    reduce为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:

    1、accumulator 累计器
    2、currentValue 当前值
    3、currentIndex 当前值的索引
    4、selfArray数组本身

    回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
    特别注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。

    如果调用reduce函数的数组为空且没有提供initialValue,会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。

    reduce方法使用示例

    参数累加

        // 不传入initialValue参数
        let arr1 = [1,3, , ,5]
        let newArr = arr1.reduce((acc, cur, index, selfArr) => {
          console.log({acc, cur, index})
          return acc + cur
        })
        console.log(newArr)
        // {acc: 1, cur: 3, index: 1}
        // {acc: 4, cur: 5, index: 4}
        // 9
    
        // 传入initialValue参数
        let newArr1 = arr1.reduce((acc, cur, index) => {
          console.log({acc, cur, index})
          return acc + cur
        }, 0)
        console.log(newArr1)
        // {acc: 0, cur: 1, index: 0}
        // {acc: 1, cur: 3, index: 1}
        // {acc: 4, cur: 5, index: 4}
        // 9
    

    上述代码的最终结果都是返回数组中每个元素相加的和,区别就是第一组代码没有传入initialValue 参数,第二组传入了initialValue 参数。
    根据打印结果可以看出,第一组没有传入initialValue参数的代码从arr1数组中索引为1的元素开始执行callback函数,一共执行了两次,并且acc初始值为数组的第一个元素。第二组传入initialValue 参数的代码,从arr1原数组中索引值为0的元素开始执行并且acc初始值为传入的initialValue的值。两组代码都没有为arr1原数组中的空值执行callback函数。

    数组对象结构的参数累加

        let arr2 = [
          {
            num: 1,
          },
          {
            num: 5,
          },
          {
            num: 7,
          }
        ]
        const newArr2 = arr2.reduce((acc, cur, index) => {
          return acc + cur.num
        }, 0)
        console.log(newArr2) 
        // 13
    

    上述代码是循环原数组arr2中每一项,并将每一项里面num的值进行相加,并且返回最后相加的结果。

    数组去重

        let arr3 = [1,2,1,1,3,5,2]
        const newArr3 = arr3.reduce((acc, cur) => {
          if (!acc.includes(cur)) acc.push(cur)
          return acc
        }, [])
        console.log(newArr3)
        //  [1, 2, 3, 5]
    

    上述代码 执行时初始参数传入一个空数组,然后开始从原数组arr3的第一个元素开始执行callback函数,每次都会利用数组的includes方法判断当前元素是否已经存在传入的数组里面,最后返回传入的数组赋值给acc参数。最后的结果就是已经去重好的新数组newArr3。

    对象分类

        let arr4 = [
          { name: '小红', age: 21 },
          { name: '小绿', age: 20 },
          { name: '小蓝', age: 20 },
          { name: '大白', age: 19 }
        ];
        const newArr4 = arr4.reduce((acc, cur, index) => {
          if (!acc[cur.age]) acc[cur.age] = []
          acc[cur.age].push(cur)
          return acc
        }, {})
        console.log(newArr4)
        // {
        //   19: [{ name: '大白', age: 19 }],
        //   20: [{name: "小绿", age: 20}, {name: "小蓝", age: 20}],
        //   21: [{name: "小红", age: 21}]
        // }
    

    上述代码将数据列表根据age进行分类,同样age的数据合并组成key:value形式展示出来。

    计算数组中元素出现的次数

        let arr5 = [1,2,3,1,2,1]
        const newArr5 = arr5.reduce((acc, cur) => {
          acc[cur]? acc[cur] ++: acc[cur] = 1
          return acc
        }, {})
        console.log(newArr5)
        // {1: 3, 2: 2, 3: 1}
    

    上述代码利用对象中key – value数据形式来计算得出数组中每个元素出现的次数。最后在来看下空数组和数组只有一个参数时的值:

        // 数组为空,传入initialValue初始值时和只有一个参数没有传入初始值时
        console.log([].reduce((acc, cur) => {
          console.log(acc, cur)
          return cur
        }, 0)) 
        // 0
    
        console.log([1].reduce((acc, cur) => {
          console.log(acc, cur)
          return 10
        }))
        // 1
    

    下面根据上述描述和使用来模拟实现我们自己的reduce方法。

    步骤思路

    1、 将方法添加到Array的原型上
    2、 传入回调函数形参和初始值形参
    3、 判断initialValue 初始值是否传入
    4、 判断原数组的元素是不是空值,来调用callback函数
    5、 将每次执行的callback函数的返回值赋值给accumulator
    6、 返回accumulator

    实现代码

        Array.prototype.myReduce = function(callback, initialValue) {
          let accumulator,initIndex, length = this.length
          // 判断initialValue初始参数有没有传入
          if (initialValue || initialValue === 0) {
            // 空数组时直接返回传入的初始参数
            if (length === 0) return initialValue
            initIndex = 0
            accumulator = initialValue
          } else {
            // 空数组时报错
            if (length === 0) throw new TypeError('xxxxxxxxx')
            // 原数组只有一个元素时,返回此元素
            if (length === 1) return this[0]
            initIndex = 1
            accumulator = this[0]
          }
          for (let index = initIndex; index < length; index++) {
            // 通过hasOwnProperty方法剔除空值,然后将传入的callback函数的值赋值给accumulator累计参数
            if(this.hasOwnProperty(index)) accumulator = callback(accumulator, this[index], index, this)
          }
          return accumulator
        }
    

    测试验证

        Array.prototype.myReduce = function(callback, initialValue) {
          let accumulator,initIndex, length = this.length
          // 判断initialValue初始参数有没有传入
          if (initialValue || initialValue === 0) {
            // 空数组时直接返回传入的初始参数
            if (length === 0) return initialValue
            initIndex = 0
            accumulator = initialValue
          } else {
            // 空数组时报错
            if (length === 0) throw new TypeError('xxxxxxxxx')
            // 原数组只有一个元素时,返回此元素
            if (length === 1) return this[0]
            initIndex = 1
            accumulator = this[0]
          }
          for (let index = initIndex; index < length; index++) {
            // 通过hasOwnProperty方法剔除空值,然后将传入的callback函数的值赋值给accumulator累计参数
            if(this.hasOwnProperty(index)) accumulator = callback(accumulator, this[index], index, this)
          }
          return accumulator
        }
    
        // 不传入initialValue参数
        let arr1 = [1,3, , ,5]
        let newArr = arr1.myReduce((acc, cur, index, selfArr) => {
          console.log({acc, cur, index})
          return acc + cur
        })
        console.log(newArr)
        // {acc: 1, cur: 3, index: 1}
        // {acc: 4, cur: 5, index: 4}
        // 9
    
        // 传入initialValue参数
        let newArr1 = arr1.myReduce((acc, cur, index) => {
          console.log({acc, cur, index})
          return acc + cur
        }, 0)
        console.log(newArr1)
        // {acc: 0, cur: 1, index: 0}
        // {acc: 1, cur: 3, index: 1}
        // {acc: 4, cur: 5, index: 4}
        // 9
    
        let arr2 = [
          {
            num: 1,
          },
          {
            num: 5,
          },
          {
            num: 7,
          }
        ]
        const newArr2 = arr2.myReduce((acc, cur, index) => {
          return acc + cur.num
        }, 0)
        console.log(newArr2) 
        // 13
    
        let arr3 = [1,2,1,1,3,5,2]
        const newArr3 = arr3.myReduce((acc, cur) => {
          if (!acc.includes(cur)) acc.push(cur)
          return acc
        }, [])
        console.log(newArr3)
        //  [1, 2, 3, 5]
    
        let arr4 = [
          { name: '小红', age: 21 },
          { name: '小绿', age: 20 },
          { name: '小蓝', age: 20 },
          { name: '大白', age: 19 }
        ];
        const newArr4 = arr4.myReduce((acc, cur, index) => {
          if (!acc[cur.age]) acc[cur.age] = []
          acc[cur.age].push(cur)
          return acc
        }, {})
        console.log(newArr4)
        // {
        //   19: [{ name: '大白', age: 19 }],
        //   20: [{name: "小绿", age: 20}, {name: "小蓝", age: 20}],
        //   21: [{name: "小红", age: 21}]
        // }
    
        
        let arr5 = [1,2,3,1,2,1]
        const newArr5 = arr5.myReduce((acc, cur) => {
          acc[cur]? acc[cur] ++: acc[cur] = 1
          return acc
        }, {})
        console.log(newArr5)
        // {1: 3, 2: 2, 3: 1}
    
        // 数组为空,传入initialValue初始值时和只有一个参数没有传入初始值时
        console.log([].myReduce((acc, cur) => {
          console.log(acc, cur)
          return cur
        }, 0))
        // 0
    
        console.log([1].myReduce((acc, cur) => {
          console.log(acc, cur)
          return 10
        }))
        // 1
    

    使用自己模拟实现的方法打印结果和原方法一致。

    相关文章

      网友评论

        本文标题:js中数组reduce方法的使用和实现

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