JavaScript数组的reduce()的定义和用法

JavaScript数组的reduce()的定义和用法

  • Array.prototype.reduce() 定义:reduce()方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

  • reducer函数接收4个参数:

    • Accumulator(acc):累计器
    • Current Value(cur):当前值
    • Current Index(idx):当前索引
    • Source Array(src):源数组

    您的reducer函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。

    语法: arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]);
    • callback:执行数组中每个值(如果没有提供 initialValue则第一值除外)的函数,包括四个参数:

      • accumulator: 累计器累计回调的返回值;它是上一次调用回调时返回的累计值,或者 initialValue;

      • currentValue:数组中正在处理的元素;

      • index 可选: 数组中正在处理的当前元素的索引,如果提供了initialValue,则起始索引号为0,否则从索引 1 起始;

      • array 可选:调用 reduce()的数组;

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

        返回值: 函数累计处理的结果;

    描述

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

    • accumulator 累计器
    • currentValue 当前值
    • currentIndex 当前索引
    • array 数组

    回调函数第一次执行时,accumulator和currentValue的取值有两种情况:

    • 如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;

    • 如果没有提供initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值;

    注意:如果没有提供initialValue,reduce会从索引 1 的地方开始执行 callback方法,跳过第一个索引,如果提供initialValue,从索引0开始。

    如果没有提供initialValue, 可能有如下几种输出:

        var maxCallback = (acc, cur) => Math.max(acc.x, cur.x)
        var maxCallback2 = (max, cur) => Math.max(max, cur)
    
        // reduce() 没有初始值
        let result1 = [ { x: 2 }, { x: 22 }, { x: 42 } ].reduce(maxCallback) // NaN
        let result2 = [ { x: 2 }, { x: 22 }            ].reduce(maxCallback) // 22
        let result3 = [ { x: 2 }                       ].reduce(maxCallback) // { x: 2 }
        // let result4 = [                                ].reduce(maxCallback) // TypeError
        console.log(result1) // NaN
        console.log(result2) // 22
        console.log(result3) // { x: 2 }
        // console.log(result4) // TypeError
    
        // map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行
        let mapReduce = [ { x: 2 }, { x: 42 } ].map(el => el.x).reduce(maxCallback2, -Infinity)
        console.log('mapReduce', mapReduce) // 42
    复制代码

    如果数组为空且没有提供initialValue,会抛出TypeError;

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

    reduce() 如何运行?

    假如运行下段reduce()代码:

    [0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
        return accumulator + currentValue;
    })
    复制代码

    callback会被调用四次,每次调用的参数和返回值值如下表:

    callback accumulator currentValue currentIndex array return value
    first call 0 1 1 [0, 1, 2, 3, 4] 1
    second call 1 2 2 [0, 1, 2, 3, 4] 3
    third call 3 3 3 [0, 1, 2, 3, 4] 6
    fourth call 6 4 4 [0, 1, 2, 3, 4] 10

    由于reduce返回的值将是最后一次回调返回值(10)。

    我们还可以使用 箭头函数 来替代完整的函数。下面的代码将产生与上面的代码相同的输出:

    [0, 1, 2, 3, 4].reduce((prev, curr) => perv + curr);


    如果你打算提供一个初始值作为reduce() 方法的第二个参数,以下是运行过程及结果:

    [0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
            return accumulator + currentValue
    }, 10)
    复制代码
    callback accumulator currentValue currentIndex array return value
    firse call 10 0 0 [0, 1, 2, 3, 4] 10
    second call 10 1 1 [0, 1, 2, 3, 4] 11
    third call 11 2 2 [0, 1, 2, 3, 4] 13
    fourth call 13 3 3 [0, 1, 2, 3, 4] 16
    fifth call 16 4 4 [0, 1, 2, 3, 4] 20

    这种情况下,reduce() 返回的值是20。

    reduce() 实用的用法:

    浏览器支持情况:
    image.png

    1. 求数组中所有值的和:

      	let initialValue = 0;    
      	let total = [0, 1, 2, 3, 4].reduce((acc, cur) => acc + cur, initialValue);
      	console.log(total); // 10 
      复制代码
    2. 累加对象数组里的值(求对象里的指定属性值的和)

      	let initialValue = 0;
          let total = [
              {subject: 'Math', score: 90},
              {subject: 'Chinese', score: 90},
              {subject: 'English', score: 100},
          ].reduce((acc, cur) => {
              return acc + cur.score
          }, initialValue);
          console.log(total); // 280
      复制代码
    3. 将二维数组转化为一维数组

      	let arr = [[0,1], [2,3], [4,5]]
          arr.reduce((acc, cur) => {
              return acc.concat(cur)
          }, [])
          // [0, 1, 2, 3, 4, 5]
      复制代码
    4. 计算数组中每个元素出现的次数

          let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
      
          let countedNames = names.reduce((allNames, name) => {
              if (name in allNames) {
                  allNames[name]++
              } else {
                  allNames[name] = 1
              }
              return allNames
          }, {})
      
          console.log('countedNames', countedNames) // {Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
      复制代码
    5. 按属性对object分类

          let people = [
              { name: 'Alice', age: 21 },
              { name: 'Max', age: 20 },
              { name: 'Jane', age: 20 }
          ];
          function groupBy(objectArray, property) {
              return objectArray.reduce((acc, obj) => {
                  let key = obj[property]
                  if (!acc[key]) {
                      acc[key] = []
                  }
                  acc[key].push(obj)
                  return acc
              }, {})
          }
          let groupedPeople = groupBy(people, 'age');
          console.log('groupedPeople', groupedPeople)
      复制代码

      image-20210429004131347

    6. 数组去重

          let myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd']
          let myOrderedArray = myArray.reduce((acc, cur) => {
              if (acc.indexOf(cur) === -1) {
                  acc.push(cur)
              }
              return acc
          }, [])
          console.log('myOrderedArray', myOrderedArray) // ["a", "b", "c", "e", "d"]
      复制代码
    7. 求数组项最大值

      	let arr = [1, 2, 3, 4];
          let maxNum = arr.reduce((acc, cur) => {
              return Math.max(acc, cur)
          })
          console.log('maxNum', maxNum) // 4
      复制代码
    8. 使用扩展运算符和initialValue绑定包含在对象数组中的数组

          // friends - 对象数组
          // where object field "books" - list of favorite books
          var friends = [{
            name: 'Anna',
            books: ['Bible', 'Harry Potter'],
            age: 21
          }, {
            name: 'Bob',
            books: ['War and peace', 'Romeo and Juliet'],
            age: 26
          }, {
            name: 'Alice',
            books: ['The Lord of the Rings', 'The Shining'],
            age: 18
          }];
      
          // allbooks - list which will contain all friends' books +
          // additional list contained in initialValue
          var allbooks = friends.reduce(function(prev, curr) {
            return [...prev, ...curr.books];
          }, ['Alphabet']);
      
          // allbooks = [
          //   'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
          //   'Romeo and Juliet', 'The Lord of the Rings',
          //   'The Shining'
          // ]
      复制代码
    9. 使用reduce实现map

      	if (!Array.prototype.mapUsingReduce) {
              Array.prototype.mapUsingReduce = function(callback, thisArg) {
                  return this.reduce(function(mappedArray, currentValue, index, array) {
                      mappedArray[index] = callback.call(thisArg, currentValue, index, array)
                      return mappedArray
                  }, [])
              }
          }
          [1, 2, , 3].mapUsingReduce(
            (currentValue, index, array) => currentValue + index + array.length
          ) // [5, 7, , 10]
      复制代码

    参考链接:

    MDN参考地址MDN

    WEB前端参考web前端

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享