JavaScript里的reduce
一、语法
数组.reduce(function(累计值, 当前元素, 当前索引, 原数组) {// 处理逻辑,返回新的累计值return 新累计值;
}, 初始值);
-
参数说明:
- 回调函数:必选,用于处理每个元素并更新累计值。
累计值(accumulator)
:上一次回调的返回值(或初始值)。当前元素(currentValue)
:当前遍历的数组元素。当前索引(currentIndex)
:可选,当前元素的索引。原数组(array)
:可选,调用reduce()
的原数组。
初始值(initialValue)
:可选,第一次调用回调时的累计值
初始值。
- 回调函数:必选,用于处理每个元素并更新累计值。
-
返回值:最终的累计值(单个值)。
二、用法
1. 数组求和(最基础)
const numbers = [1, 2, 3, 4, 5];// 无初始值:累计值初始为数组第一个元素(1),从第二个元素(2)开始遍历
const sum1 = numbers.reduce(function(acc, curr) {return acc + curr; // 累计值 = 上一次累计值 + 当前元素
});
console.log(sum1); // 15(1+2+3+4+5)// 有初始值:累计值初始为 0,从第一个元素(1)开始遍历
const sum2 = numbers.reduce(function(acc, curr) {return acc + curr;
}, 0);
console.log(sum2); // 15
2. 数组求积
const numbers = [1, 2, 3, 4];
const product = numbers.reduce(function(acc, curr) {return acc * curr;
}, 1); // 初始值为 1(乘法的单位元)
console.log(product); // 24(1×2×3×4)
3. 统计元素出现次数
const fruits = ['苹果', '香蕉', '苹果', '橙子', '香蕉', '苹果'];// 初始值为 {}(空对象,用于存储 {元素: 次数})
const count = fruits.reduce(function(acc, curr) {// 如果对象中已有该元素,次数+1;否则初始化为1acc[curr] = (acc[curr] || 0) + 1;return acc; // 返回更新后的对象
}, {});console.log(count);
// { 苹果: 3, 香蕉: 2, 橙子: 1 }
4. 数组去重
const arr = [1, 2, 2, 3, 3, 3];// 初始值为 [](空数组,用于存储去重后元素)
const uniqueArr = arr.reduce(function(acc, curr) {// 如果累计数组中没有当前元素,则添加if (!acc.includes(curr)) {acc.push(curr);}return acc;
}, []);console.log(uniqueArr); // [1, 2, 3]
5. 二维数组扁平化
const nestedArr = [1, [2, 3], [4, [5, 6]], 7];// 初始值为 [],递归扁平化数组
const flatArr = nestedArr.reduce(function(acc, curr) {// 如果当前元素是数组,递归 reduce;否则直接添加return acc.concat(Array.isArray(curr) ? curr.reduce(arguments.callee, []) : curr);
}, []);console.log(flatArr); // [1, 2, 3, 4, 5, 6, 7]
// ES6 中可直接用 arr.flat(Infinity),但 reduce 更灵活
三、注意
-
初始值的重要性
- 若提供初始值:回调从第一个元素开始执行,
累计值
初始为初始值
。 - 若不提供初始值:
累计值
初始为数组第一个元素,回调从第二个元素开始执行。 - 风险:空数组且无初始值时会报错;非空数组但逻辑依赖初始值时可能出错(如求和时数组第一个元素为非数字)。
const emptyArr = []; // emptyArr.reduce((acc, curr) => acc + curr); // 报错:Reduce of empty array with no initial value emptyArr.reduce((acc, curr) => acc + curr, 0); // 0(安全)
- 若提供初始值:回调从第一个元素开始执行,
-
回调必须返回累计值
若回调未返回值,累计值会变为undefined
,导致后续计算错误:const numbers = [1, 2, 3]; const wrong = numbers.reduce(function(acc, curr) {// 忘记 return,累计值会变为 undefinedacc + curr; }, 0); console.log(wrong); // undefined
四、与其他方法的对比
reduce()
是“万能方法”,可模拟map
、filter
等功能:// 用 reduce 模拟 map(返回新数组) const numbers = [1, 2, 3]; const mapped = numbers.reduce((acc, curr) => {acc.push(curr * 2);return acc; }, []); // [2, 4, 6]// 用 reduce 模拟 filter(筛选元素) const filtered = numbers.reduce((acc, curr) => {if (curr > 1) acc.push(curr);return acc; }, []); // [2, 3]