TypeScript — forEach 和 map 的区别

forEach 和 map 的区别

This article is extracted from the chat log with AI. Please identify it with caution.

在 TypeScript(以及 JavaScript)中,forEachmap 都是数组方法,但它们有重要的区别。了解这些区别对于编写高效和正确的代码至关重要。

1. 基本区别 #

特性forEachmap
返回值undefined新数组
是否修改原数组可能(取决于回调函数)不修改原数组
链式调用不支持(返回 undefined)支持(返回数组)
用途遍历执行操作转换数组元素

2. 使用示例 #

forEach 示例 #

// 使用 forEach 遍历数组
const numbers = [1, 2, 3, 4, 5];
let sum = 0;

numbers.forEach(num => {
  sum += num;
  console.log(num); // 执行副作用操作
});

console.log(sum); // 15
console.log(numbers); // [1, 2, 3, 4, 5] - 原数组不变

map 示例 #

// 使用 map 转换数组
const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(num => {
  return num * 2; // 返回新值
});

console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] - 原数组不变

3. 性能差异 #

// 性能测试示例
const largeArray = Array.from({length: 1000000}, (_, i) => i);

console.time('forEach');
largeArray.forEach(item => {
  // 执行操作但不返回任何内容
});
console.timeEnd('forEach');

console.time('map');
const newArray = largeArray.map(item => {
  return item; // 返回新值
});
console.timeEnd('map');

通常情况下,forEachmap 稍微快一些,因为它不需要创建和返回新数组。

4. 使用场景对比 #

适合使用 forEach 的场景 #

// 1. 执行副作用操作
const users = [{name: 'Alice'}, {name: 'Bob'}, {name: 'Charlie'}];

users.forEach(user => {
  console.log(user.name); // 只是打印,不需要返回值
});

// 2. 修改外部变量
let total = 0;
const prices = [10, 20, 30];

prices.forEach(price => {
  total += price;
});

// 3. 操作DOM元素
const elements = document.querySelectorAll('.item');
elements.forEach(el => {
  el.classList.add('active');
});

适合使用 map 的场景 #

// 1. 转换数组元素
const numbers = [1, 2, 3];
const squared = numbers.map(n => n * n); // [1, 4, 9]

// 2. 提取对象属性
const users = [
  {id: 1, name: 'Alice'},
  {id: 2, name: 'Bob'}
];
const names = users.map(user => user.name); // ['Alice', 'Bob']

// 3. 链式操作
const result = numbers
  .map(n => n * 2)      // [2, 4, 6]
  .filter(n => n > 3)   // [4, 6]
  .map(n => n + 1);     // [5, 7]

5. 高级用法 #

使用索引参数 #

// forEach 和 map 都接收索引作为第二个参数
const fruits = ['apple', 'banana', 'cherry'];

fruits.forEach((fruit, index) => {
  console.log(`${index}: ${fruit}`);
});

const indexedFruits = fruits.map((fruit, index) => {
  return `${index}-${fruit}`;
});
// ['0-apple', '1-banana', '2-cherry']

使用 this 参数 #

// 两者都可以指定回调函数中的 this 值
const multiplier = {
  factor: 2,
  multiply(numbers: number[]) {
    return numbers.map(function(n) {
      return n * this.factor;
    }, this); // 指定 this
  }
};

console.log(multiplier.multiply([1, 2, 3])); // [2, 4, 6]

6. 注意事项 #

  1. 提前终止:两者都不能使用 breakcontinue,但可以使用 return 跳过当前迭代(在 forEach 中)或返回特定值(在 map 中)。

  2. 异步操作

    // 两者都不适合异步操作,但可以使用 Promise.all 与 map 结合
    async function processArray(array: number[]) {
      // 错误的做法 - 不会等待异步操作完成
      array.forEach(async num => {
        await someAsyncOperation(num);
      });
    
      // 正确的做法 - 使用 Promise.all 和 map
      await Promise.all(array.map(async num => {
        return await someAsyncOperation(num);
      }));
    }
    
  3. 稀疏数组:两者都会跳过稀疏数组中的空位。

总结 #

  • 使用 forEach 当你只是想遍历数组并执行一些操作(副作用),而不需要返回值。
  • 使用 map 当你需要基于原数组创建一个新数组,转换每个元素。
  • map 返回一个新数组,可以链式调用其他数组方法,而 forEach 返回 undefined
  • 在性能敏感的场景中,如果不需要创建新数组,forEach 可能比 map 更高效。

选择正确的方法可以使代码更清晰、更高效,并避免不必要的内存分配。

本文共 997 字,创建于 Aug 26, 2025

相关标签: TypeScript, JavaScript, Frontend, ByAI