JavaScript 中 forEach 和 map 的区别是什么?
比较 JavaScript 中的 forEach 和 map 方法在使用场景、返回值及对原数组的影响上的区别。
forEach
和 map
都是 JavaScript 中用于遍历数组的方法,但它们在使用方式、返回值、是否修改原数组等方面有显著区别。以下是两者的详细对比:
🛠 1. 核心区别
特性 | map |
forEach |
---|---|---|
返回值 | ✅ 返回新数组(元素为回调返回值) | ❌ 返回 undefined |
修改原数组 | ❌ 不修改原数组 | ⚠️ 可通过索引修改原数组元素 |
链式调用 | ✅ 可链式调用(如结合 filter ) |
❌ 不支持链式调用 |
性能 | 🔥 通常更快(约快 70%) | ⏱ 较慢 |
📝 2. 使用场景
map
适用场景:
需基于原数组生成新数组(如数据转换、提取属性),或需链式操作(如arr.map(...).filter(...)
)。const numbers = [1, 2, 3]; const squares = numbers.map(num => num * num); // [1, 4, 9]
forEach
适用场景:
仅需遍历数组执行操作(如打印、更新外部变量),或需通过索引修改原数组(非整个元素替换)。const arr = [10, 20, 30]; arr.forEach((item, index) => { if (item === 20) arr[index] = 200; // 直接修改原数组:arr 变为 [10, 200, 30] });
⚠️ 3. 修改原数组的注意事项
- 基本数据类型:
forEach
中直接修改item
无效(因item
是值拷贝),必须通过arr[index]
修改:const nums = [1, 2, 3]; nums.forEach((num, index, arr) => { num = num * 10; // ❌ 无效 arr[index] = num * 10; // ✅ 有效:nums 变为 [10, 20, 30] });
- 引用数据类型:
修改item
的属性会影响原数组(因item
是地址拷贝),但替换整个item
无效:const users = [{ name: "Alice" }, { name: "Bob" }]; users.forEach((user, index, arr) => { user.name = "Carol"; // ✅ 修改属性:原数组同步更改 user = { name: "Dave" }; // ❌ 替换整个对象无效 arr[index] = { name: "Dave" }; // ✅ 需通过索引替换 });
🔧 4. 代码示例对比
// 示例 1:生成新数组 vs 仅遍历
const arr = [1, 2, 3];
const mapped = arr.map(x => x * 2); // [2, 4, 6](新数组)
arr.forEach(x => console.log(x)); // 打印 1, 2, 3(无返回值)
// 示例 2:链式调用
const result = arr.map(x => x + 1)
.filter(x => x > 2); // [3, 4](链式操作)
// 示例 3:修改原数组
const items = [{ count: 1 }, { count: 2 }];
items.forEach(item => item.count++); // ✅ 原数组变为 [{count:2}, {count:3}]
💎 总结
方法选择 | 原因 |
---|---|
需生成新数组 → map |
返回新数组且不污染原数据,适合函数式编程 |
需修改原数组 → forEach |
可通过索引直接修改,但注意数据类型限制 |
仅遍历不修改 → forEach |
语义更清晰,避免无意义的新数组内存开销 |