前言
最近看项目代码的时候老是会见到数组的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 被调用四次,每次调用的参数和返回值如下表:
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((accumulator, currentValue, currentIndex, array) => { return accumulator + currentValue; }, 10 ); // 提供初始值为 10
执行上述代码,每次调用的参数和返回值如下表:
callback | accumulator | currentValue | currentIndex | array | return value |
---|---|---|---|---|---|
first 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
。
二.用途
介绍几个常用的用法
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 }] // }
评论(0)