reduce()
方法很强大,在很多时候都可以用到,这篇文章将会以十二种场景来演示它的使用方法,这将涵盖其90%以上的场景。还有很重要的一点,相信我,90%以上的人都不能熟练的运用reduce方法,所以掌握了它,你就可以出去装杯了哈哈。
1. 语法介绍
reduce()
方法的基础语法如下:
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
其中,arr
是调用reduce()
方法的数组。这个方法执行一个“reducer”回调函数(callback
)在数组的每个元素上,最终将它们“归纳”为一个单一的输出值。
reduce()
方法接受两个参数:
callback
函数:在数组的每一项上执行的函数,接受四个参数:accumulator
:累加器累积回调的返回值。currentValue
:当前处理的数组元素。index
(可选):当前处理的数组元素的索引。array
(可选):调用reduce()
方法的数组本身。
initialValue
(可选):作为第一次调用callback
函数时accumulator
参数的值。
2. 分析参数
accumulator
和currentValue
accumulator
是一个“累加器”,它是callback
函数从数组的第一项到当前项的累积返回值。在reduce()
的第一次调用中,accumulator
可以是initialValue
(如果提供了此参数),或者是数组的第一个元素(如果没有提供initialValue
)。
currentValue
是数组中正在处理的当前元素。在reduce()
的迭代过程中,它依次表示数组的每一个元素。
index
和array
index
是可选参数,表示currentValue
在数组中的索引。reduce()
的迭代从数组的第一项(或第二项,如果未提供initialValue
)开始,因此index
从0
(或1
)开始。
array
是可选参数,表示调用reduce()
方法的数组本身,这在某些情况下用于引用整个数组。
initialValue
initialValue
是可选的初始值。提供initialValue
时,accumulator
将从这个值开始累积;否则,accumulator
将从数组的第一个元素开始累积,并且迭代从数组的第二个元素开始。
3. 注意事项
返回值
在使用reduce()
时,一定要注意回调函数必须有返回值,这个返回值将被用作下一次迭代的accumulator
值。如果回调函数没有返回值,那么accumulator
将会是undefined
,这可能会导致逻辑错误。
空数组
对空数组使用reduce()
时,如果没有提供initialValue
,则会抛出TypeError。因此,当你不确定数组是否为空时,需要提供initialValue
。
性能
尽管reduce()
非常强大,但在处理大型数组或复杂的迭代逻辑时,应考虑其对性能的影响。在某些情况下,其他方法(如循环)可能更高效。
言归正传,接下来展示15种使用场景!
1. 数组求和与求积
// 数组求和
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((total, value) => total + value, 0);
console.log(sum); // 输出: 10
// 数组求积
const product = numbers.reduce((total, value) => total * value, 1);
console.log(product); // 输出: 24
2. 计算数组对象中某属性的总和
const items = [
{ name: 'Book', price: 15 },
{ name: 'Pen', price: 5 },
{ name: 'Notebook', price: 20 }
];
const total = items.reduce((sum, item) => sum + item.price, 0);
console.log(total); // 输出: 40
3. 实现数组的平均值计算
const grades = [87, 94, 68, 100];
const average = grades.reduce((total, grade, index, array) => {
total += grade;
if (index === array.length - 1) {
return total / array.length;
} else {
return total;
}
}, 0);
console.log(average); // 输出: 87.25
4. 数组去重
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = numbers.reduce((unique, item) => {
return unique.includes(item) ? unique : [...unique, item];
}, []);
console.log(uniqueNumbers); // 输出: [1, 2, 3, 4, 5]
5. 将数组转换为对象
const fruits = ['apple', 'banana', 'cherry'];
const fruitObj = fruits.reduce((obj, fruit, index) => {
obj[fruit] = index;
return obj;
}, {});
console.log(fruitObj); // 输出: { apple: 0, banana: 1, cherry: 2 }
6. 统计数组元素出现的次数
const names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
const nameCount = names.reduce((count, name) => {
count[name] = (count[name] || 0) + 1;
return count;
}, {});
console.log(nameCount); // 输出: { Alice: 2, Bob: 1, Tiff: 1, Bruce: 1 }
7. 找出数组中的最大值或最小值
// 最大值
const numbersMax = [10, 5, 100, 2, 1000];
const max = numbersMax.reduce((a, b) => Math.max(a, b));
console.log(max); // 输出: 1000
// 最小值
const numbersMin = [10, 5, 100, 2, 1000];
const min = numbersMin.reduce((a, b) => Math.min(a, b));
console.log(min); // 输出: 2
8. 分组
const people = [
{ name: 'Alice', age: 21 },
{ name: 'Max', age: 20 },
{ name: 'Jane', age: 20 }
];
const groupByAge = people.reduce((group, person) => {
const { age } = person;
if (!group[age]) {
group[age] = [];
}
group[age].push(person);
return group;
}, {});
console.log(groupByAge);
/*
输出:
{
20: [{ name: 'Max', age: 20 }, { name: 'Jane', age: 20 }],
21: [{ name: 'Alice', age: 21 }]
}
*/
9. 链式调用函数
const increment = x => x + 1;
const double = x => x * 2;
const functions = [increment, double];
const result = functions.reduce((value, func) => func(value), 3);
console.log(result); // 输出: 8
10. 展平数组
const nestedArray = [1, [2, [3, [4,5]]], 6];
const flatArray = nestedArray.reduce((acc, val) => acc.concat(Array.isArray(val) ? flattenArray(val) : val), []);
console.log(flatArray); // 输出: [1, 2, 3, 4, 5, 6]
### 11. 实现Promise串行执行
```javascript
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const tasks = [delay(1000), delay(2000), delay(3000)];
tasks.reduce((prev, task) => {
return prev.then(() => task);
}, Promise.resolve()).then(() => console.log('All tasks completed!'));
12. 对象属性求和
const result = [
{ subject: 'math', score: 78 },
{ subject: 'english', score: 82 },
{ subject: 'science', score: 95 }
];
const totalScore = result.reduce((total, current) => total + current.score, 0);
console.log(totalScore); // 输出: 255
13. 构造查询字符串
const params = { name: 'John', age: 30, city: 'New York' };
const queryString = Object.entries(params).reduce((str, [key, value], index) => {
const delimiter = index === 0 ? '?' : '&';
return `${str}${delimiter}${key}=${value}`;
}, '');
console.log(queryString); // 输出: "?name=John&age=30&city=New York"
14. 条件累加
const numbers = [1, 2, 3, 4, 5, 6];
const evenSum = numbers.reduce((sum, num) => {
return num % 2 === 0 ? sum + num : sum;
}, 0);
console.log(evenSum); // 输出: 12
15. 实现自定义的map()
或filter()
// 自定义 map 使用 reduce
const numbersMap = [1, 2, 3, 4, 5];
const doubled = numbersMap.reduce((acc, cur) => {
acc.push(cur * 2);
return acc;
}, []);
console.log(doubled); // 输出: [2, 4, 6, 8, 10]
// 自定义 filter 使用 reduce
const numbersFilter = [1, 2, 3, 4, 5];
const evens = numbersFilter.reduce((acc, cur) => {
if (cur % 2 === 0) {
acc.push(cur);
}
return acc;
}, []);
console.log(evens); // 输出: [2, 4]