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

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

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

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值