浅谈 map 和 forEach 的区别(是否原始数组?❌❌❌)

这个问题你的第一反应是什么?

很多人都会说map不会改变原数组,而forEach可以改变原数组。❌

看完这篇文章,相信你对这个问题会有一个新的理解!

forEach

先来看看TC39forEach的介绍:

浅谈 map 和 forEach 的区别(是否原始数组?❌❌❌)

注意框起来的段落:

  • forEach 不会直接更改被调用的对象,但调用 callbackfn 时可能会更改对象。
  • forEach 所处理的元素范围是在首次调用 callbackfn 之前设置的。调用 forEach 开始后追加到数组中的元素将不会被 callbackfn 访问。如果数组中的现有元素被更改,传递给 callbackfn 的值将是 forEach 访问这些元素时的值。

给出如下示例验证:

被遍历数据:

const numberArray = [1, 2, 3, 4];
const objectArray = [{ age: 15 }, { name: 24 }, { name: 30 }];
  • 修改原数组:
    • 对于原始类型,需要通过使用原数组+索引的方式,这种方式无论在什么情况都是可以改变值的,但不能直接赋值
    • 对于引用类型,可以直接修改其属性
numberArray.forEach((value, index, array) => {
  array[index] *= 2;
}); //[2,4,6,8]

objectArray.forEach((value, index, array) => {
  value.age += 2;
});[{ age: 17 }, { age: 26 }, { age: 32 }]
  • 遍历范围 及 当前遍历的值:
    • 调用次数在调用回调前就确定了
    •   numberArray.forEach((value, index) => {
        numberArray.push(index);
        }); //[1,2,3,4,0,1,2,3]
      
    • 每次使用的value都是调用时的值
    • numberArray.forEach((value, index) => {
      //遍历第一个元素时将第二个元素修改为-1
      if (index === 0) {
        numberArray[1] = -1;
      }
      //遍历第二个元素时输出
      if (index === 1) {
        console.log(value); //-1
      }
      });
      

除了这些之外:

  • forEach回调的返回值永远是undefined
  • forEach每次的循环可以使用return跳过

map

再来看看TC39对map的描述:

浅谈 map 和 forEach 的区别(是否原始数组?❌❌❌)

完全一样,这里其实就已经推翻了之前所说的:map不会改变原数组,而forEach可以改变原数组。

因此上面的对于forEach的示例,在使用map时效果一样;

难道mapforEach就没有区别了?

当然不是:

  • 区别一:map有返回值,返回的是每次调用回调的返回值组成的新数组
  • 区别二:mapreturn调用时,返回值会被收集;

深度对比

接下来将给出mapforEach底层算法的步骤,并标注区别;

浅谈 map 和 forEach 的区别(是否原始数组?❌❌❌)

重点关注map的逻辑:在map执行回调之前,就会创建一个与原数组长度相等的数组,然后每次回调的返回值将加入到新数组中这也是为什么map不支持跳过循环的原因

总结

在我们了解了其工作原理和底层算法设计之后,就能总结出两者的区别了

相同

  • 对于修改原数组:mapforEach都可以修改原数组,因为我们可以访问到原始数组,那么对于原始类型的修改就可以利用array[index]进行赋值。
  • 对于循环的跳出
    • mapforEach都不能完全中断循环,即不存在for循环中调用的break的效果,但是你可以使用try catch在回调中手动抛出异常就可以中断循环了。
    • 使用return就可以达到在for循环中调用continue的效果,
      • 但是对于map来说,一定要注意return的值将被收集到新数组

不同

  • 对于返回值:
    • map存在返回值,其返回值为一个与原数组等长的新数组,且其中每个元素为每次调用回调的返回值
    • forEach的返回值永远是undefined
  • 对于设计目的:
    • forEach往往使用在仅希望遍历数组,利用数组的元素来完成某些工作
    • map往往是为了根据原始数组的元素生成一个新的数组

原文链接:https://juejin.cn/post/7315126195335462938 作者:Ys_OoO

(0)
上一篇 2023年12月23日 上午10:15
下一篇 2023年12月23日 上午10:26

相关推荐

发表回复

登录后才能评论