前言:
今天大家对“js数组map和foreach区别”大约比较讲究,各位老铁们都需要知道一些“js数组map和foreach区别”的相关资讯。那么小编在网摘上汇集了一些对于“js数组map和foreach区别””的相关文章,希望各位老铁们能喜欢,咱们一起来学习一下吧!为什么要写这么一篇文章,原因是今天下午水群的时候,有个小伙伴分享自己的面试题,其中一个是forEach和map的区别,其实是蛮简单,蛮基础的一道题,但是他是这么回答的:
❝
一个会改变原数组,一个不会。
❞
我当场就懵了,我以为是整活,谁知道是认真的,并且给我发了一篇文章。
我看完更蚌埠住了,那么多对的文章,你偏偏挑个错的。
然后我发现,真的很多人都这么认为的,那这真的是一件很可怕的事情,明明你自己试一下就知道了,甚至有不少文章都是这么写的,但是我也看到了不错的文章,写的已经不错了。
那么咱们,就这个简单的问题,咱们浅浅地说一下~
区别map会返回一个新的数组,而forEach不会
简单的区别我们可以在MDN上看看:
简单来说,map会返回一个新的数组,而forEach不会,实际上是因为forEach不会返回任何值(实际上返回的是undefined),而map是有返回值的,是一个新数组。
我们可以简单手写一下,看的会更直观一些。
「map」
function myMap(array, callback) { const result = []; for (let i = 0; i < array.length; i++) { result.push(callback(array[i], i, array)); } return result;}
「forEach」
function myForEach(array, callback) { for (let i = 0; i < array.length; i++) { callback(array[i], i, array); }}
再简单点对比:
❝
forEach和map的实现原理相似。它们都是通过遍历数组,对数组的每个元素执行特定的函数。区别主要在于它们处理函数返回值的方式不同。forEach 忽略函数的返回值,而 map 则将函数的返回值收集到一个新的数组中。
❞
在内部,这两个函数可能会使用一个类似于下面的for循环来遍历数组:
for (let i = 0; i < array.length; i++) { callback(array[i], i, array); // callback是forEach或map的参数函数}
在map的内部实现中,还会有一个新的数组用于收集每次调用回调函数的结果。这个新的数组最后会被返回:
let newArray = [];for (let i = 0; i < array.length; i++) { newArray.push(callback(array[i], i, array)); // callback 是 map 的参数函数}return newArray;
❝
那么这个时候,有人可能会想,那我使用forEach的时候,加个return不就得了,咱们先不说能不能实现,就是真实现了,我觉得是没什么实际意义的,尽管你可以在回调函数中添加返回语句,但这个返回值不会被 forEach 方法捕获或使用。
❞
那接下来咱们看看能不能实现吧:
const array = [1, 2, 3] const result = array.forEach((element) => { return element * 2; // 这个返回值不会被 forEach 捕获或使用 }); console.log(result); // 输出: undefined
那么咱们使用map呢?
const array = [1, 2, 3] const result = array.map((element) => { return element * 2; // 这个返回值会被 map 捕获或使用 }); console.log(result); // 输出: [2, 4, 6]
到这里,我相信大家就能明白了。
map和forEach会不会改变原数组
这需要看我们面对的数据类型,会分为基础数据类型和引用类型。
「基础数据类型」
「forEach」
const array = [1, 2, 3, 4]; array.forEach(item => { item = item + 1 }) console.log(array); // [1,2,3,4]
「map」
const array = [1, 2, 3, 4]; array.map(item => { item = item + 1 }) console.log(array); // [1,2,3,4]
我们发现是不会进行改变的。
「引用类型」
const arr = [{ name: 'shaka', age: 23 }, { name: 'virgo', age: 18 }] arr.forEach(item => { if (item.name === 'shaka') { item.age = 100 } }) console.log(arr); //[{name: 'shaka', age: 100}, {name: 'virgo', age: 18}]
map就不再写了,也是会改变的。
所以重点来了,我们回到这个问题:问js的forEach和map的区别,显而易见一个会改变原数组,一个不会,这个答案毫无疑问是错误的。
❝
这里我们其实应该思考的是,为什么基础数据类型不会更改,引用类型会更改。
❞
这是因为在使用forEach和map方法时,对引用类型元素的修改会直接反映在原始数组中。这是因为引用类型的元素实际上存储的是引用(内存地址),而非值本身。因此,通过引用可以访问和修改原始数组中的元素。
number,string,Boolean,null,undefined它们在栈内存中直接存储变量与值。
我们再回头看这个:
为什么他这个修改了呢?
❝
因为使用的是arr[index]。相当于你平常的 数组名[第几项]=值。这样自然是可以修改的。
❞
还有哪些区别呢foreach可以跳出循环,return 语句可以当前回调函数中返回,而map不能,只能遍历完整个数组。foreach不支持链式调用,而map支持链式调用,可以继续对返回的新数组进行操作。
这里注意:forEach方法无法通过使用break语句来中断循环,break语句用于中断循环的功能只适用于for循环或while循环。
这里给大家点例子吧,一下就能看懂了~
// 使用 forEach 跳出当前循环 const array1 = [1, 2, 3, 4, 5]; let sum1 = 0; array1.forEach((element) => { if (element === 3) { return; // 使用 return 跳出循环 } console.log(element); //1,2,4,5 sum1 += element; }); console.log(sum1); // 输出: 12 // 使用 map 无法中断循环 const array2 = [1, 2, 3, 4, 5]; const newArray = array2.map((element) => { if (element === 3) { // 使用 return 语句无法中断 map 循环 return; } return element * 2; }); console.log(newArray); // 输出: [2, 4, undefined, 8, 10] // map 方法支持链式调用 const array3 = [1, 2, 3, 4, 5]; const doubledSum = array3 .map((element) => element * 2) .reduce((accumulator, currentValue) => accumulator + currentValue, 0); console.log(doubledSum); // 输出: 30
const array = [1, 2, 3, 4, 5]; let sum = 0; array.forEach((element) => { if (element === 3) { break; // 使用 break 无法中断 forEach 循环 } sum += element; }); console.log(sum); // 此行代码不会执行,因为上面的代码会抛出错误 //for循环则可以 const array = [1, 2, 3, 4, 5]; let sum = 0; for (let i = 0; i < array.length; i++) { const element = array[i]; if (element === 3) { break; // 使用 break 中断 for 循环 } sum += element; } console.log(sum); // 输出: 3
作为数组最常见的几个api之一,我觉得搞懂它是有必要的,当然,我这里说的其实是不全的,因为网上的文章较多,文档也很详细,这篇文章主要的目的是帮助一些小伙伴纠正一下~
最后,如有哪里不正确,请您指正~