reduce()
对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值。
reducer 函数接收4个参数:
- Accumulator (acc) (累计器)
- Current Value (cur) (当前值)
- Current Index (idx) (当前索引)
- Source Array (src) (源数组)
您的 reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
回调函数第一次执行时,accumulator
和currentValue
的取值有两种情况:
- 如果调用
reduce()
时提供了initialValue
,accumulator
取值为initialValue
,currentValue
取数组中的第一个值; - 如果没有提供
initialValue
,那么accumulator
取数组中的第一个值,currentValue
取数组中的第二个值。 - 如果没有提供
initialValue
,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue
,从索引0开始。 - 如果数组为空且没有提供initialValue,会抛出TypeError
- 如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
var maxCallback = (acc, cur) => Math.max(acc.x, cur.x)
var maxCallback2 = (max, cur) => Math.max(max, cur);
// reduce() 没有初始值
[{x: 22}, {x: 42}].reduce(maxCallback); // 42
[{x: 22}].reduce(maxCallback); // { x: 22 }
[].reduce(maxCallback); // TypeError
// map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行
[{x: 22}, {x: 42}].map(el => el.x)
.reduce(maxCallback2, -Infinity)
reduce() 如何运行
假如运行下段reduce()
代码:
[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array){
return accumulator + currentValue;
});
===
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr );
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()
方法的第二个参数,以下是运行过程及结果:
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue
}, 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 |
数组里所有值的和
var total = [0, 1, 2, 3].reduce(
(acc, cur) => acc + cur, 0
)
累加对象数组里的值
要累加对象数组中包含的值,必须提供初始值,以便各个item正确通过你的函数。
var sum = [{x: 1}, {x: 2}, {x: 3}].reduce(
(accumulator, currentValue) => accumulator + currentValue.x, 0
)
console.log(sum) // logs 6
将二维数组转化为一维
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
(acc, cur) => acc.concat(cur), []
)
// [0, 1, 2, 3, 4, 5]
计算数组中每个元素出现的次数
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']
var countedNames = names.reduce(function (allNames, name) {
if (name in allNames) {
allNames[name]++
} else {
allNames[name] = 1
}
return allNames
}, {})
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
按属性对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 is:
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }
使用扩展运算符和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'
// ]
数组去重
var myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'];
var myOrderedArray = myArray.reduce(function (accumulator, currentValue) {
if (accumulator.indexOf(currentValue) === -1) {
accumulator.push(currentValue);
}
return accumulator
}, [])
console.log(myOrderedArray);
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current) => {
if(init.length === 0 || init[init.length-1] !== current) {
init.push(current);
}
return init;
}, []);
console.log(result); //[1,2,3,4,5]
使用 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]
reduceRight()
- 接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
- 如果调用
reduceRight
时提供了initialValue
参数,则accumulator
等于initialValue
,currentValue
等于数组中的最后一个值。 - 如果没有提供
initialValue
参数,则accumulator
等于数组最后一个值,currentValue
等于数组中倒数第二个值。 - 如果数组为空,且没有提供
initialValue
参数,将会抛出一个TypeError 错误。
如果数组只有一个元素且没有提供
initialValue
参数,或者提供了initialValue
参数,但是数组为空将会直接返回数组中的那一个元素或initialValue
参数,而不会调用callback
。
[0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) {
return previousValue + currentValue;
});
回调将会被调用四次,每次调用的参数及返回值如下:
previousValue | currentValue | index | array | return value | |
---|---|---|---|---|---|
first call | 4 | 3 | 3 | [0,1,2,3,4] | 7 |
second call | 7 | 2 | 2 | [0,1,2,3,4] | 9 |
third call | 9 | 1 | 1 | [0,1,2,3,4] | 10 |
fourth call | 10 | 0 | 0 | [0,1,2,3,4] | 10 |
reduceRight
返回值是最后一次调用回调的返回值(10)。
如果提供了一个 initialValue
参数,则结果如下:
[0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) {
return previousValue + currentValue;
}, 10);
previousValue | currentValue | index | array | return value | |
---|---|---|---|---|---|
first call | 10 | 4 | 4 | [0,1,2,3,4] | 14 |
second call | 14 | 3 | 3 | [0,1,2,3,4] | 17 |
third call | 17 | 2 | 2 | [0,1,2,3,4] | 19 |
fourth call | 19 | 1 | 1 | [0,1,2,3,4] | 20 |
fifth call | 20 | 0 | 0 | [0,1,2,3,4] | 20 |
reduceRight
返回值为 20。