面试题:问js的forEach和map的区别

简介: 面试题:问js的forEach和map的区别

前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

【国庆头像】- 国庆爱国 程序员头像!总有一款适合你!

前言

为什么要写这么一篇文章,原因是今天下午水群的时候,有个小伙伴分享自己的面试题,其中一个是foreachmap的区别,其实是蛮简单,蛮基础的一道题,但是他是这么回答的

一个会改变原数组,一个不会

我当场就懵了,我以为是整活,谁知道是认真的,并且给我发了一篇文章

我看完更蚌埠住了,那么多对的文章,你偏偏挑个错的

然后我发现,真的很多人都这么认为的,那这真的是一件很可怕的事情,明明你自己试一下就知道了,甚至有不少文章都是这么写的,但是我也看到了不错的文章,写的已经不错了

那么咱们,就这个简单的问题,咱们浅浅地说一下~

区别

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);
  }
}

再简单点对比

forEachmap 的实现原理相似。它们都是通过遍历数组,对数组的每个元素执行特定的函数。区别主要在于它们处理函数返回值的方式不同。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的区别,显而易见一个会改变原数组,一个不会这个答案毫无疑问是错误的

这里我们其实应该思考的是,为什么基础数据类型不会更改,引用类型会更改

这是因为在使用 forEachmap 方法时,对引用类型元素的修改会直接反映在原始数组中。这是因为引用类型的元素实际上存储的是引用(内存地址),而非值本身。因此,通过引用可以访问和修改原始数组中的元素。

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之一,我觉得搞懂它是有必要的,当然,我这里说的其实是不全的,因为网上的文章较多,文档也很详细,这篇文章主要的目的是帮助一些小伙伴纠正一下~

最后,如有哪里不正确,请您指正~

致谢补充

这里是文章发出一段时间的致谢补充,很感谢评论区的一些建议和指正,主要是我在forEach这里,说出了它可以跳出循环(本次循环),大家进行了指正

前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

【国庆头像】- 国庆爱国 程序员头像!总有一款适合你!

相关文章
|
1月前
|
索引
ES5常见的数组方法:forEach ,map ,filter ,some ,every ,reduce (除了forEach,其他都有回调,都有return)
ES5常见的数组方法:forEach ,map ,filter ,some ,every ,reduce (除了forEach,其他都有回调,都有return)
|
19天前
|
编译器
经典面试题:变量的声明和定义有什么区别
在编程领域,变量的“声明”与“定义”是经典面试题之一。声明告诉编译器一个变量的存在,但不分配内存,通常包含变量类型和名称;而定义则为变量分配内存空间,一个变量必须至少被定义一次。简而言之,声明是告知变量形式,定义则是实际创建变量并准备使用。
|
18天前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
54 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
3天前
|
存储 JavaScript
foreach和map
foreach和map
8 0
|
1月前
|
存储 JavaScript 前端开发
`forEach()`方法和`map()`方法哪个执行效率更高?
`forEach()`方法和`map()`方法哪个执行效率更高?
|
9天前
|
存储 JavaScript 前端开发
js中map属性
js中map属性
10 0
|
10天前
|
前端开发 小程序 JavaScript
面试官:px、em、rem、vw、rpx 之间有什么区别?
面试官:px、em、rem、vw、rpx 之间有什么区别?
12 0
|
1月前
数组方法中的`forEach()`方法和`map()`方法有什么区别?
数组方法中的`forEach()`方法和`map()`方法有什么区别?
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
83 2