map 与 forEach 区别

JavaScript 数组方法 map 和 forEach 的区别与使用场景

问题

mapforEach 都是数组遍历方法,它们有什么区别?分别在什么场景下使用?

解答

基本区别

const numbers = [1, 2, 3, 4, 5];

// forEach: 遍历数组,无返回值
const forEachResult = numbers.forEach((num) => {
  return num * 2;
});
console.log(forEachResult); // undefined

// map: 遍历数组,返回新数组
const mapResult = numbers.map((num) => {
  return num * 2;
});
console.log(mapResult); // [2, 4, 6, 8, 10]

链式调用

const numbers = [1, 2, 3, 4, 5];

// map 可以链式调用
const result = numbers
  .map((num) => num * 2) // [2, 4, 6, 8, 10]
  .filter((num) => num > 5) // [6, 8, 10]
  .reduce((sum, num) => sum + num, 0); // 24

console.log(result); // 24

// forEach 无法链式调用,因为返回 undefined

使用场景

const users = [
  { name: 'Alice', age: 20 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 30 },
];

// forEach: 执行副作用操作(打印、修改外部变量、DOM 操作等)
let totalAge = 0;
users.forEach((user) => {
  console.log(user.name); // 打印每个用户名
  totalAge += user.age; // 累加年龄
});

// map: 数据转换,生成新数组
const names = users.map((user) => user.name);
console.log(names); // ['Alice', 'Bob', 'Charlie']

const userCards = users.map((user) => ({
  ...user,
  displayName: `${user.name} (${user.age}岁)`,
}));
console.log(userCards);
// [
//   { name: 'Alice', age: 20, displayName: 'Alice (20岁)' },
//   { name: 'Bob', age: 25, displayName: 'Bob (25岁)' },
//   { name: 'Charlie', age: 30, displayName: 'Charlie (30岁)' }
// ]

性能差异

const largeArray = Array.from({ length: 1000000 }, (_, i) => i);

// 如果不需要返回值,forEach 更合适
// 因为 map 会创建新数组,占用额外内存
console.time('forEach');
largeArray.forEach((num) => {
  // 执行某些操作
  Math.sqrt(num);
});
console.timeEnd('forEach');

console.time('map');
largeArray.map((num) => {
  // 执行某些操作
  Math.sqrt(num);
});
console.timeEnd('map');
// map 会稍慢,因为需要创建和填充新数组

中断遍历

const numbers = [1, 2, 3, 4, 5];

// forEach 和 map 都无法用 break 中断
// 如果需要中断,使用 for...of 或 some/every
numbers.forEach((num) => {
  if (num === 3) return; // 只能跳过当前迭代,不能中断整个循环
  console.log(num);
});
// 输出: 1, 2, 4, 5

// 使用 some 实现中断
numbers.some((num) => {
  if (num === 3) return true; // 返回 true 中断循环
  console.log(num);
  return false;
});
// 输出: 1, 2

关键点

  • 返回值map 返回新数组,forEach 返回 undefined
  • 用途map 用于数据转换,forEach 用于执行副作用
  • 链式调用map 支持链式调用,forEach 不支持
  • 性能:不需要返回值时用 forEach,避免 map 创建无用数组
  • 中断:两者都无法用 break 中断,需要中断时用 for...ofsome/every