在学习Javascript
繁多的数组方法时,map
和forEach
两个方法经常被拿来对比,两者用法比较相似但在一些细节上又有所区别.JS高程3对二者叙述分别如下:
forEach()
:对数组中的每一项运行给定函数,这个方法没有返回值
map()
:对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组.
两者区别
1. 返回值不同
-
map()
: 返回一个新数组,包含回调函数对每个元素的处理结果javascriptconst numbers = [1, 2, 3]; const doubled = numbers.map(num => num * 2); console.log(doubled); // [2, 4, 6]
-
forEach()
: 没有返回值(返回undefined
)javascriptconst result = numbers.forEach(num => num * 2); console.log(result); // undefined
2.在回调中显式修改原数组时的差异
在 JavaScript 中,map()
和 forEach()
方法本身不会自动修改原始数组,但它们确实提供了在回调函数中修改原数组的可能性。这种修改就是"显式修改"。
2.1. 不修改原数组的正常用法
javascript
const numbers = [1, 2, 3];
// map - 不修改原数组
const doubled = numbers.map(num => num * 2);
console.log(numbers); // [1, 2, 3] (未改变)
console.log(doubled); // [2, 4, 6]
// forEach - 不修改原数组
numbers.forEach(num => num * 2);
console.log(numbers); // [1, 2, 3] (未改变)
2.2. 显式修改原数组的情况
javascript
const numbers = [1, 2, 3];
// 在forEach回调中显式修改原数组
numbers.forEach((num, index, arr) => {
arr[index] = num * 2; // 显式修改原数组
});
console.log(numbers); // [2, 4, 6] (已改变)
// 在map回调中显式修改原数组
const anotherArray = [1, 2, 3];
const result = anotherArray.map((num, index, arr) => {
arr[index] = num + 1; // 显式修改原数组
return num * 2;
});
console.log(anotherArray); // [2, 3, 4] (已改变)
console.log(result); // [2, 4, 6] (map仍返回新数组)
注意事项
- 不推荐这样做:显式修改原数组会使代码难以理解和维护
- 可能导致意外行为:特别是在链式调用时
- 考虑使用其他方法 :如果需要修改原数组,可以考虑
splice
、直接赋值等更明确的方式
-
map()
方法返回一个全新的数组,其中包含转换后的元素和相同数量的数据。这类似于React修改state时要保持不可变性一样.因而callback
最好遵循纯函数原则. -
对于
forEach()
,即使它返回undefined
,它也会用callback
改变原始数组。同样类比于React,使用forEach
不用遵循不可变性,因而可以在callback
里面使用副作用.
小结一下,我们可以理解为 map()
依赖于不变性,而 forEach()
是一个 mutator 方法。
3.是否能链式调用
map()
: 可以链式调用其他数组方法forEach()
: 不能链式调用,因为它返回undefined
javascript
const myAwesomeArray = [1, 2, 3, 4, 5]
myAwesomeArray.forEach(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>> Uncaught TypeError: Cannot read property 'reduce' of undefined
myAwesomeArray.map(x => x * x).reduce((total, value) => total + value)
//>>>>>>>>>>>>>return value: 55
4.性能差异
map()
: 稍慢于forEach()
,因为它需要创建并返回新数组forEach()
: 性能稍好,适合纯遍历场景