JavaScript 中的数组方法 reduce:从计算总和到数据转换

98 阅读2分钟

一、一句话定义

reduce = 数组的「压缩器」

它能够将数组中的元素逐个处理,最终「压缩」成一个值(可以是数字、字符串、对象、数组等)


二、基础语法

array.reduce(
  (accumulator, currentValue, index, array) => {
    // 处理逻辑
    return updatedAccumulator;
  },
  initialValue // 初始值(可选)
);

参数详解

参数名作用描述是否可选
accumulator累积值(上一次回调的返回值)必选
currentValue当前处理的数组元素必选
index当前元素的索引可选
array原始数组可选
initialValue初始累积值(不传则默认用第一项)可选

三、示例

1. 计算总和(购物车结算)

const cart = [
  { product: "Phone", price: 800, amount: 1 },
  { product: "Laptop", price: 1200, amount: 1 },
  { product: "Headphones", price: 100, amount: 2 }
];

const total = cart.reduce((sum, item) =>
  sum + item.price * item.amount,
  0 // 初始值
);

console.log(`Total: $${total}`); // Total: $2200

2. 数据格式转换(数组 → 对象)

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" }
];

const userMap = users.reduce((map, user) => {
  map[user.id] = user.name;
  return map;
}, {});

console.log(userMap);
// { 1: "Alice", 2: "Bob" }

3. 复杂数据聚合(分组统计)

const orders = [
  { product: "Phone", category: "Electronics" },
  { product: "Shirt", category: "Clothing" },
  { product: "Laptop", category: "Electronics" }
];

const categoryCount = orders.reduce((count, order) => {
  count[order.category] = (count[order.category] || 0) + 1;
  return count;
}, {});

console.log(categoryCount);
// { Electronics: 2, Clothing: 1 }

四、与 map 的对比分析

特性reducemap
输出类型任意类型(灵活)新数组(固定)
状态管理支持累积值(accumulator每次迭代独立
适用场景聚合、分组、复杂转换一对一元素映射
性能单次遍历完成复杂操作需要额外操作处理复杂逻辑

五、使用技巧与最佳实践

1. 初始值的重要性

// 无初始值(默认用第一项)
[1, 2, 3].reduce((sum, num) => sum + num); // 6

// 有初始值
[].reduce((sum, num) => sum + num, 0); // 0(安全)

2. 链式操作优化

// 传统方式(多次遍历)
const total = cart
  .map(item => item.price * item.amount)
  .reduce((sum, price) => sum + price, 0);

// 优化版(单次遍历)
const total = cart.reduce((sum, item) =>
  sum + item.price * item.amount, 0);

3. 处理异步操作

const fetchData = async (urls) => {
  return urls.reduce(async (promise, url) => {
    const results = await promise;
    const data = await fetch(url).then(res => res.json());
    return [...results, data];
  }, Promise.resolve([]));
};

六、总结与建议

  • 适用场景:数据聚合、复杂转换、状态累积

  • 性能优势:单次遍历完成复杂操作

  • 学习曲线:比 map/filter 稍复杂,但功能更强大

  • 建议

    • 始终提供初始值以避免意外错误
    • 避免过度嵌套,保持回调函数简洁
    • 在需要状态累积时优先选择 reduce