JavaScript 中的map()和forEach():详尽解析与对比
1. map()和forEach()的区别和理解
Array.prototype.map()
和Array.prototype.forEach()
都是用于遍历数组中的每一项,但它们有一些区别。
在JavaScript的数组操作中,
map()
和forEach()
是两个非常实用的方法,它们都能遍历数组中的每一个元素,但它们之间存在一些重要的区别,这些差异决定了在不同场景下应该选择哪一个方法。接下来,我们将通过定义、实例、共同点及差异点四个方面,全面剖析这两个方法。到底有什么区别呢?
MDN上对Map和ForEach的定义
forEach()
: 针对每一个元素执行提供的函数(executes a provided function once for each array element)。除了抛出异常以外,没有办法中止或跳出 forEach() 循环。如果你需要中止或跳出循环,forEach() 方法不是应当使用的工具。 map(): callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。map()
: 创建一个新的数组,其中每一个元素由调用数组中的每一个元素执行提供的函数得来(creates a new array with the results of calling a provided function on every element in the calling array)。map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。
实例
让我们通过具体的代码实例来直观感受两者的用法和效果。
使用 map()
const numbers = [1, 4, 9, 16];
const doubledNumbers = numbers.map(number => number * 2);
console.log(doubledNumbers); // 输出:[2, 8, 18, 32]
console.log(numbers); // 输出:[1, 4, 9, 16],原数组未变
在上面的例子中,map()
将每个元素乘以2,并返回了一个新数组。
使用 forEach()
const letters = ['a', 'b', 'c'];
let result;
letters.forEach(letter => {
console.log(letter);
result = letter.toUpperCase();
});
console.log(result); // 输出:undefined
console.log(letters); // 输出:['a', 'b', 'c'],原数组未变
这里,forEach()
只负责遍历和打印每个字母,最终的 result
为 undefined
,因为它不返回任何值。
共同点
- 循环遍历:两者都会遍历数组的每个元素。
- 参数传递:都可以接收一个回调函数,该函数可以获取到当前元素
item
、当前索引index
和原始数组input
。 - this绑定:回调函数中的
this
默认绑定为全局对象(在浏览器中通常是window
)。
差异点
1.map
- 有返回值,可以return出来一个length和原数组一致的数组(内容可能包含undefined、null等)
const array = [1,2,4,6,10];
const res = array.map((item,index,input) => { return item*10; })
console.log(res); // [10,20,40,60,100]
console.log(array); // [1,2,4,6,10] 不变
- 参数:item数组中的当前项,index当前项的索引,input原始数组
- 区别:map的回调函数中支持return返回值,return的是一个数组,相当于把数组中的这一项进行改变(并不影响原来的数组,只是相当于把原数组克隆了一份,把克隆这一份的数组中的对应项改变了 );
2.forEach
- 没有返回值,返回结果为undefined
const array = [1,2,4,6,10];
const res = array.forEach((item,index,input) => {
return input[index] = item*10;
})
console.log(res); // undefined
console.log(array); // [10,20,40,60,100]原数组修改为变动后
- 参数:item数组中的当前项,index当前项的索引,input原始数组;
- 数组中有几项,那么传递进去的匿名回调函数就需要执行几次 理论上这个方式是没有返回值的,只是遍历数组中的每一项,不对原来数组进行修改,但是可以自己通过数组的索引来修改原来的数组
- 其实上面结果输出是有问题的
在 forEach
循环中,对于数组 ['a', 'b', 'c']
的每个元素,都会执行一次箭头函数。在这个函数中,letter.toUpperCase()
被调用以将当前字母转换成大写,然后这个大写形式的字母被赋值给 result
。
- 第一次迭代:
letter
是'a'
,result
设置为'A'
。 - 第二次迭代:
letter
是'b'
,result
设置为'B'
。 - 第三次迭代:
letter
是'c'
,result
设置为'C'
。
由于 result
是一个变量,它可以在每次迭代中更新其值。在最后一次迭代后,result
的值保持为 'C'
,这就是为什么在循环结束后打印 result
会输出 'C'
的原因。
尝试使用 map()
循环,通过索引修改原数组值
- 理论上,
map()
不会修改原数组,但如果在回调函数中通过索引访问并修改原数组,会发生什么呢?
Javascript
深色版本
const array = [1, 2, 4, 6, 10];
const res = array.map((item, index, input) => {
input[index] = item * 10;
});
5console.log(res); // 输出:[undefined, undefined, undefined, undefined, undefined]
6console.log(array); // 输出:[10, 20, 40, 60, 100],原数组被修改
- 从这段代码中我们可以看到,
map()
返回的数组由undefined
组成,因为回调函数中并没有返回任何值。然而,原数组array
被修改了,这是因为我们在回调函数中通过索引修改了它。
总结
forEach()
方法不会返回执行结果,而是返回 undefined
。它被调用时,不会改变原数组,尽管在回调函数中可以修改原数组。
map()
方法会分配内存空间存储新数组并返回。map()
不修改调用它的原数组本身,但在回调执行时可以改变原数组。
了解这些细节对于正确使用这两个方法以及优化代码性能至关重要。在编写代码时,根据你是否需要返回一个新的数组,或者是否需要执行一些副作用操作,选择正确的迭代方法。
转载自:https://juejin.cn/post/7391744486978207794