Skip to main content

reduce()

reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

Try it

计算数组所有元素的总和:

reducer 逐个遍历数组元素,每一步都将当前元素的值与上一步的计算结果相加(上一步的计算结果是当前元素之前所有元素的总和)——直到没有更多的元素被相加。

const array1 = [1, 2, 3, 4];

// 0 + 1 + 2 + 3 + 4
const initialValue = 0;

const sumWithInitial = array1.reduce(
(previousValue, currentValue) => previousValue + currentValue,
initialValue
);

console.log(sumWithInitial);
// expected output: 10

你也可以写成箭头函数的形式:

let total = [0, 1, 2, 3].reduce(
(previousValue, currentValue) => previousValue + currentValue,
0
);

累加对象数组里的值

要累加对象数组中包含的值,必须提供 initialValue,以便各个 item 正确通过你的函数。

let initialValue = 0;
let sum = [{ x: 1 }, { x: 2 }, { x: 3 }].reduce(function (
previousValue,
currentValue
) {
return previousValue + currentValue.x;
},
initialValue);

console.log(sum); // logs 6

你也可以写成箭头函数的形式:

let initialValue = 0;
let sum = [{ x: 1 }, { x: 2 }, { x: 3 }].reduce(
(previousValue, currentValue) => previousValue + currentValue.x,
initialValue
);

console.log(sum); // logs 6

将二维数组转化为一维

let flattened = [
[0, 1],
[2, 3],
[4, 5],
].reduce(function (previousValue, currentValue) {
return previousValue.concat(currentValue);
}, []);
// flattened is [0, 1, 2, 3, 4, 5]

你也可以写成箭头函数的形式:

let flattened = [
[0, 1],
[2, 3],
[4, 5],
].reduce(
(previousValue, currentValue) => previousValue.concat(currentValue),
[]
);

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

let 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 is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

按属性对 object 分类

let people = [
{ name: "Alice", age: 21 },
{ name: "Max", age: 20 },
{ name: "Jane", age: 20 },
];

function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}

let groupedPeople = groupBy(people, "age");
// groupedPeople is:
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }

提取对象数组中数组

let people = [
{ name: "Alice", age: 21 },
{ name: "Max", age: 20 },
{ name: "Jane", age: 20 },
];

function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}

let groupedPeople = groupBy(people, "age");
// groupedPeople is:
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }

数组去重

let myArray = ["a", "b", "a", "b", "c", "e", "e", "c", "d", "d", "d", "d"];
let myArrayWithNoDuplicates = myArray.reduce(function (
previousValue,
currentValue
) {
if (previousValue.indexOf(currentValue) === -1) {
previousValue.push(currentValue);
}
return previousValue;
},
[]);

console.log(myArrayWithNoDuplicates);

使用 .reduce() 替换 .filter()/.map()

使用 Array.filter() 和 Array.map() 会遍历数组两次,而使用具有相同效果的 Array.reduce() 只需要遍历一次,这样做更加高效。(如果你喜欢 for 循环,你可用使用 Array.forEach() 以在一次遍历中实现过滤和映射数组)

const numbers = [-5, 6, 2, 0];

const doubledPositiveNumbers = numbers.reduce((previousValue, currentValue) => {
if (currentValue > 0) {
const doubled = currentValue * 2;
previousValue.push(doubled);
}
return previousValue;
}, []);

console.log(doubledPositiveNumbers); // [12, 4]

按顺序运行 Promise

/**
* Runs promises from array of functions that can return promises
* in chained manner
*
* @param {array} arr - promise arr
* @return {Object} promise object
*/
function runPromiseInSequence(arr, input) {
return arr.reduce(
(promiseChain, currentFunction) => promiseChain.then(currentFunction),
Promise.resolve(input)
);
}

// promise function 1
function p1(a) {
return new Promise((resolve, reject) => {
resolve(a * 5);
});
}

// promise function 2
function p2(a) {
return new Promise((resolve, reject) => {
resolve(a * 2);
});
}

// function 3 - will be wrapped in a resolved promise by .then()
function f3(a) {
return a * 3;
}

// promise function 4
function p4(a) {
return new Promise((resolve, reject) => {
resolve(a * 4);
});
}

const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10).then(console.log); // 1200