实现reduce

reduce

参数
  • callback(accumulator上次调用callback结果, currentValue当前元素的值, currentIndex当前元素索引,array:调用的数组)
  • initialValue 第一次调用回调时初始化accumulator 的值
每次调用的时候 返回值都传递到下一次调用中

这里acc就是前面的元素累加的结果

注意这里首次回调将索引为0的作为acc索引为1的作为cur

 //reduce
    let arr = [0, 1, 2, 3, 4]
    //累加arr再加10
    let result = arr.reduce((acc, cur) => acc + cur, 10) //20
    result = arr.reduce((acc, cur) => {
      console.log(acc, cur);//01 12 33 64
      return acc + cur
    }) //10
不对稀疏数组空槽进行调用

map forEach filter some every一样
稀疏数组空槽

this始终是undefine
  • 这里非严格模式是window非严格模式
  • 严格模式是undefined严格模式

严格模式下 函数没有被call apply bind 或者通过对象调用 显示绑定this 都默认指向undefined

'use strict' //加在开头

    //严格模式this始终是undefined
    function fn1() {
      console.log(this); //undefined
    }
    fn1()
基于原数组长度迭代

注意这里打印的是cur 第一次回调的curarr[1]
arr改变了 但是result还是打印原数组迭代的结果

  let arr = [0, 1, 2, 3]
    let result = arr.reduce((acc, cur) => {
      arr.push(cur + 1)
      console.log(cur);//123
      return acc + cur
    }) //
    console.log(result, arr); //6 (7) [0, 1, 2, 3, 2, 3, 4]
边界情况
  • 提供 initialValue 且数组不为空 调用回调函数
    arr = [1]
    result = arr.reduce((acc, crr) => {
      console.log(acc, crr); //10 1
      return acc + crr
    }, 10)
    console.log(result);//11
返回单个值 不执行回调函数
  • 数组只有一个元素且未提供 initialValue 返回单个值 不调用回调函数
  arr = [1]
    result = arr.reduce((acc, crr) => {
      console.log(acc, crr); //这里没有打印
      return acc + crr
    })
    console.log(result);//1 
  • 提供了 initialValue且数组为空 不调用回调函数
arr = []
    result = arr.reduce((acc, crr) => {
      console.log(acc, crr);
      return acc + crr
    }, 10)
    console.log(result);//10
用法

这里参考了mdn

统计对象中值的出现次数

这里的count表示如果出现过相应元素就把次数放进去 如果没出现过就是0 最后都+1
返回的对象{展开前面迭代的对象,当前元素:次数+1}

同一对象字面量内的重复属性直接被覆盖
对象属性名有唯一性 key必须唯一覆盖

  //统计对象中值的出现次数
    arr = [1, 2, 2, 3, 2, 4]
    result = arr.reduce((all, num) => {
      const count = all[num] ?? 0
      //返回一个对象
      return {
        ...all,
        [num]: count + 1
      }
    }, {})
    console.log(result); //{1: 1, 2: 3, 3: 1, 4: 1}

注意 这里num是变量 所以要用[num]

迭代过程如图所示统计对象中值的出现次数

按属性给对象分组

reduce中 key作为分组键按照key进行分组 curGroup判断迭代产生的对象是否有当前处理的对象的key有的话就把那部分也放入key的值中 没有的话返回[]最后就放不进去
返回的对象{展开前面迭代的对象,分组键:[展开这一组,当前对象]}

obj = [{ name: 'a', age: 18, },
    { name: 'b', age: 19 },
    { name: 'c', age: 18, },]

    function groupBy(objArr, property) {
      return objArr.reduce((acc, obj) => {
        const key = obj[property]
        const curGroup = acc[key] ?? []
        return {
          ...acc,
          [key]: [...curGroup, obj]
        }
      }, {})
    }
    const group = groupBy(obj, 'age')
    console.log(group);
    //{18:[{ name: 'a', age: 18 },{name: 'c', age: 18}],
    //19:[{name: 'b', age: 19}]}

迭代过程如图所示
按属性给对象分组

实现

  • 判断acc迭代初始值 这里用了...iValue所以iVallue 是剩余参数数组 如果传入iVallue就为iVallue[0] 没传入就是this[0]数组的第一位 所以不执行回调函数的情况下 直接返回acc
  • 处理迭代起始位 这里采用了三元运算符 如果如果传入iVallue就从数组第1位开始迭代 start = 0 没传入此时迭代初始值是this[0]从数组的第2位开始 start = 1

这里不能用iValue的真假来判断 因为传入0的时候返回假值 所以需要用剩余参数数组的长度iValue.length > 0来判断是否传入第二个参数

  • 这里len保存原数组长度
  • 这里只有在传入iValue且数组长度>=1的时候 也就是iValue.length + this.length > 2这两个数组的长度加起来>2才执行回调函数
  • 循环遍历数组 下一次的acc就是上一次的迭代完毕的返回值
  • 最后返回acc
    代码如下
 Array.prototype.myReduce = function (callback, ...iValue) {
      let acc = iValue[0] ?? this[0] //迭代初始值
      let start = null
      start = (iValue.length > 0) ? 0 : 1
      let len = this.length //原数组长度
      //这种情况下才执行回调函数
      if (iValue.length + this.length > 2) {
        for (let i = start; i < len; i++) {
          if (this[i] !== undefined) {
            acc = callback(acc, this[i]) //下一次的acc就是上一次的迭代完毕
          }
        }
      }
      return acc
    }

测试用例如下

  //iValue参数
    arr = [1, 2, 3]
    result = arr.myReduce((acc, cur) => {
      return acc + cur
    }, 6)//12
    //不执行回调函数的情况
    arr = []
    result = arr.myReduce((acc, cur) => {
      console.log(acc, cur);
      return acc + cur
    }, 1) //1
    arr = [1]
    result = arr.myReduce((acc, cur) => {
      console.log(acc, cur);
      return acc + cur
    }) //1
    //迭代效果
    arr = [1, 2, 3, 4, 5]
    result = arr.myReduce((acc, cur) => {
      console.log(acc, cur);
      return acc + cur
    })
    let Result = arr.reduce((acc, cur) => {
      console.log('应该输出的结果', acc, cur);
      return acc + cur
    })
    console.log('输出结果比较', result, Result);
    //不对稀疏数组空槽调用
    arr = [1, 2, 3]
    arr[6] = 6
    result = arr.myReduce((acc, cur) => {
      console.log(acc, cur);
      return acc + cur
    })
    //基于原数组长度迭代
    arr = [1, 2, 3]
    result = arr.myReduce((acc, cur) => {
      arr.push(8)
      return acc + cur
    }) //6
    console.log(arr); //[1, 2, 3, 8, 8]
    //统计对象中值出现的次数
    let stats = [1, 2, 3, 2, 4]
    result = stats.myReduce((obj, num) => {
      let count = obj[num] ?? 0
      return {
        ...obj,
        [num]: count + 1
      }
    }, {})
    console.log(result);
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐