ES6之数组reduce()方法详解

·  阅读 3978

 前言

最近看项目代码的时候老是会见到数组的reduce方法刚开始没有太在意,因为知道该方法的大致用法,但是由于往后不断地学习,发现自己原来对这个方法的理解有误或者说理解不全面,为了保持我对学习的秉性——拒绝一知半解,今天特意花时间来全面的探究了一下这个方法,以下是对数组reduce()方法的介绍以及我的一些理解,希望能给大家带来帮助

一.reduce语法说明

方法介绍:

reduce() 方法对数组中的每个元素执行一个由我们提供的reducer函数,且该函数为升序执行,并将其结果汇总为单个返回值。

 参数说明:

arr.reduce(callback(accumulator, currentValue[, currentIndex [, array]])[, initialValue])
复制代码

第一个参数: callback函数

执行数组中每个值 (如果没有提供第二个参数 initialValue ,则第一个值除外)的函数,包含四个参数:

  •  accumulator: 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
  •  currentValue:数组中正在处理的元素。
  •  currentIndex可选 :数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。
  •  array可选:调用reduce()的原数组

第二个参数: initialValue可选

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

这样看起来会有点蒙,其实就是两种情况:一种情况是给了第二个参数initialValue初始值;一种是没提供初始值。

执行机制:

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

回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。

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

 举例:无初始值:

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

执行上述代码,callback 被调用四次,每次调用的参数和返回值如下表:

callbackaccumulatorcurrentValuecurrentIndexarrayreturn value
first call011[0,1,2,3,4]1
second call122[0,1,2,3,4]3
third call333[0,1,2,3,4]6
fourth call644[0,1,2,3,4]10

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

有初始值:

[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => 
{ return accumulator + currentValue; }, 10 );
// 提供初始值为 10
复制代码

 执行上述代码,每次调用的参数和返回值如下表:

callbackaccumulatorcurrentValuecurrentIndexarrayreturn value
first call1000[0,1,2,3,4]10
second call1011[0,1,2,3,4]11
third call1122[0,1,2,3,4]13
fourth call1333[0,1,2,3,4]16
fifth call1644[0,1,2,3,4]20

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

二.用途

介绍几个常用的用法

1.求和

1.1 基本数据类型求和

var total = [ 0, 1, 2, 3 ].reduce(
  ( acc, cur ) => acc + cur,
  0
);
// total  6
复制代码

1.2 引用数据类型求和 

let arr = [
  {
    value: 45,
  },
  {
    value: 88,
  },
  {
    value: 101,
  },
];
let newArr = arr.reduce((acc, cur) => {
  return acc+ cur.value;
}, 0);
console.log(newArr);   //234
复制代码

2.扁平数组

2.1二维数组转一维数组(利用concat方法可以将传入的数组参数与当前数组拼接)

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
 ( acc, cur ) => acc.concat(cur),
 []
);
// [0, 1, 2, 3, 4, 5]
复制代码

2.2多维数组转一维

let flattened = [[1, [2, 8]], [3, 4, 9], [5, [6, 10]]]
function fn(arr) {
  return arr.reduce((acc, cur) => {
    return acc.concat(Array.isArray(cur) ? fn(cur) : cur);
  }, []);
}
const newArr = fn(flattened );
console.log(newArr); //[1, 2, 8, 3, 4, 9, 5, 6, 10]
复制代码

3.累加对象里的值

let sum = [{x: 1}, {x:2}, {x:3}].reduce(
    (accumulator, currentValue) => accumulator + currentValue.x
    ,0
);
console.log(sum) //  6
复制代码

4.计算数组中每个元素出现的次数

const names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let countedNames = names.reduce(function (allNames, name) { 
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames :
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
复制代码

5.按属性对object分类

var people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];
function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    var key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}
var groupedPeople = groupBy(people, 'age');
// groupedPeople :
// { 
//   20: [
//     { name: 'Max', age: 20 }, 
//     { name: 'Jane', age: 20 }
//   ], 
//   21: [{ name: 'Alice', age: 21 }] 
// }
复制代码
收藏成功!
已添加到「」, 点击更改