reduce方法及使用场景

78 阅读3分钟

语法

arr.reduce(callback,[initialValue])

reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。

    callback (执行数组中每个值的函数,包含四个参数)
 
    1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
    2、currentValue (数组中当前被处理的元素)
    3、index (当前元素在数组中的索引)
    4array (调用 reduce 的数组)
 
    initialValue (作为第一次调用 callback 的第一个参数。)

详解 initialValue 参数

不设置初始值

 var arr = [1, 2, 3, 4];
    var sum = arr.reduce(function(prev, cur, index, arr) {
        console.log(prev, cur, index);
        return prev + cur;
    })
    console.log(arr, sum);

打印结果 上面的例子index是从1开始的,第一次的prev的值是数组的第一个值。数组长度是4,但是reduce函数循环3次。 image.png

设置初始值

    var arr = [1, 2, 3, 4];
    var sum = arr.reduce(function(prev, cur, index, arr) {
                console.log(prev, cur, index);
                return prev + cur;
            },
            0) //注意这里设置了初始值
    console.log(arr, sum);

打印结果 这个例子index是从0开始的,第一次的prev的值是我们设置的初始值0,数组长度是4,reduce函数循环4次。 image.png

提供初始值通常更安全

数组为空不设置初始值会报错

var arr = [];
    var sum = arr.reduce(function(prev, cur, index, arr) {
            console.log(prev, cur, index);
            return prev + cur;
        })
        //报错,"TypeError: Reduce of empty array with no initial value"

设置初始值不会报错

    var arr = [];
    var sum = arr.reduce(function(prev, cur, index, arr) {
        console.log(prev, cur, index);
        return prev + cur;
    }, 0)
    console.log(arr, sum); // [] 0"

结论:

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

实际应用

(1) 累加和累积

    //  累加
 const sum = (...num) => {
     return num.reduce((sum, num) => sum + num)
 }
 console.log(sum(1, 2, 3, 4, 5))

 // 累积
 const accumulator = (...nums) => {
     return nums.reduce((acc, num) => acc * num);
 };

(2)求最大值最小值

  // 原生api
  const array = [-1, 10, 6, 5];
  const max = Math.max(...array); // 10
  const min = Math.min(...array); // -1
  // reduce
  const array = [-1, 10, 6, 5];
  const max = array.reduce((max, num) => (max > num ? max : num));
  const min = array.reduce((min, num) => (min < num ? min : num));

(2)拉平嵌套数组

  // ES5 flat
 const array = [1, [2, [3, [4, [5]]]]];
 // expected output [ 1, 2, 3, 4, 5 ]
 const flatArray = array.flat(Infinity); // [1, 2, 3, 4, 5]

 //    reduce
 const flat = (array) => {
     return array.reduce(
         (acc, it) => acc.concat(Array.isArray(it) ? flat(it) : it), []
     );
 };
 const array = [1, [2, [3, [4, [5]]]]];
 const flatArray = flat(array); // [1, 2, 3, 4,

(4) 数组去重

通过includes,解构,解构分成了三种写法。

  const array = [1, 2, 1, 2, -1, 10, 11]
    const uniqueArray1 = [...new Set(array)]
    const uniqueArray2 = array.reduce((acc, it) =>
        acc.includes(it) ?
        acc :
        [...acc, it], [])
    let newArr = arr.reduce((pre, cur) => {
        if (!pre.includes(cur)) {
            return pre.concat(cur)
        } else {
            return pre
        }
    }, [])
 const arr = [10, 10, 20]
    const result = arr.reduce((acc, cur) => {
        if (acc.indexOf(cur) === -1) {
            acc.push(cur)
        }
        return acc
    }, [])
    console.log(result)

(5)数组计数 **

const count = (array) => {
        return array.reduce((acc, it) => (acc.set(it, (acc.get(it) || 0) + 1), acc), new Map())
    }
    const array = [1, 2, 1, 2, -1, 0, '0', 10, '10']
    console.log(count(array)) // Map(7) {1 => 2, 2 => 2, -1 => 1, 0 => 1, '0' => 1, …}

(6)计算数组中每个元素出现的次数

  let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

  let nameNum = names.reduce((pre, cur) => {
      if (cur in pre) {
          pre[cur]++
      } else {
          pre[cur] = 1
      }
      return pre
  }, {})
  console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1

(7)对象里属性求和

   var result = [{
       subject: 'math',
       score: 10
   }, {
       subject: 'chinese',
       score: 20
   }, {
       subject: 'english',
       score: 30
   }];

   var sum = result.reduce(function(prev, cur) {
       return cur.score + prev;
   }, 0);
   console.log(sum) //60

(8)获取对象的多个属性,然后赋给新的对象 **

  const obj = {
       a: 1,
       b: 2,
       c: 3,
       d: 4,
       e: 5
           // ...
   }

   const newObj = {
       a: obj.a,
       b: obj.b,
       c: obj.c,
       d: obj.d
           // ...
   }

reduce

 const obj = {
       a: 1,
       b: 2,
       c: 3,
       d: 4,
       e: 5

   }
   const getObjectKeys = (obj = {}, keys = []) => {

       return Object.keys(obj).reduce((acc, key) => (keys.includes(key) && (acc[key] = obj[key]), acc), {});

   }
   const newObj = getObjectKeys(obj, ['a', 'b', 'c', 'd'])
   console.log(newObj)

(9)反转字符串**

 const reverseString = (string) => {
       return string.split("").reduceRight((acc, s) => acc + s)
   }
   const string = 'fatfish'
   console.log(reverseString(string)) // hsiftaf

(10)根据指定属性,对对象数组中的对象进行分组。

(11) 结合三点运算符

(12)遍历数组,同时对符合条件的数组元素进行操作。

(13)将promise的链式操作,按照顺序执行

对多个promise链式操作进行同步顺序执行,这就对异步的嵌套执行,提供了reduce的解决方案,除了使用async/await语法外,这个在实际项目中也可以用一下

(14)开启由多个函数组成的管道

(15)用reduce模拟数组的map函数

(16)格式化搜索参数

(17)反序列化搜索参数

let search ='https://www.jb51.net/article/251863.htm?name=fatfish&age=100#/home'
let search2 = 'https://www.66152.com/answer/202207/996655.html?name=fatfish&age=100#/home'

(18)实现flat