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

news2025/5/26 8:42:28

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

地址:前端面试题库

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

前言

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

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

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

image.png

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

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

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

区别

map会返回一个新的数组,而forEach不会

简单的区别我们可以在MDN上看看

image.png

image.png

简单来说什么意思,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它们在栈内存中直接存储变量与值

我们再回头看这个

image.png

为什么他这个修改了呢

因为使用的是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这里,说出了它可以跳出循环(本次循环),大家进行了指正

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

地址:前端面试题库

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1010422.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第四阶段】kotlin语言中的数组类型

1.kotlin语言中的数组类型 类型定义IntArrayintArrayOf()DoubleArraydoubleArrayOf()LongArraylongArrayOf()ShortArrayshortArrayOf()ByteArraybyteArrayOf()FloatArrayfloatArrayOf()BooleanArraybooleanArrayOf()Array<对象类型>arrayOf() 2.Intarry常规操作的越界崩…

MySQL数据库 | 手把手教你如何去下载安装MySQL数据库

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。MySQL是一种开源的关系型数据库管理系统&#xff0c;它可以用于存储和管理大量结构化数据。它提供了广泛的功能和灵活性&#xff0c;使得它成为许多应用程序的首选数据库解决方案。为了让大家后期更好的了解MySQL数据库基础…

如何评价一门编程语言的难易程度?

编程语言是一种用于与计算机交流的工具&#xff0c;它可以让我们创造出各种各样的应用和系统。编程世界中的语言多种多样&#xff0c;但是&#xff0c;并不是所有的编程语言都一样容易学习和使用。有些语言可能需要更多的时间和精力&#xff0c;而有些语言则相对简单和直观。 …

Zabbix监控平台部署流程

Zabbix WEB、Zabbix Server、Zabbix Database放在一台服务器&#xff1b;&#xff08;192.168.10.12&#xff09;Zabbix Agent部署在被监控服务器上 &#xff08;192.168.10.11&#xff09;Zabbix Porxy 单独部署在一台服务器上&#xff08;被监控服务器少于500台可以不部署&am…

day40 设计模式、jdk8新特性

一、代理模式 为其他对象提供一种代理控制此对象的访问 若一个对象不适合直接引用另一个对象&#xff0c; 代理对象在客户端和目标对象之间起到中介作用 组成&#xff1a; 抽象角色&#xff1a;通过接口 抽象类 真实角色实现了哪些方法 代理角色&#xff1a;实现抽象角色…

function—— Verilog的函数

文章目录 前言function写法语法举例说明调用 前言 function用法说明。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 function写法 function的标准写法如下&#xff1a; function <返回值的类型或范围>(函数名);<端口说明语句> // in…

Python语言概述

​ 视频版教程 Python3零基础7天入门实战视频教程 Python作为一门非常流行的高级编程语言&#xff0c;自从22年开始&#xff0c;TIOBE编程语言排行榜Python一直排第一。 Python简洁高效&#xff0c;丰富的应用场景&#xff0c;受到广大程序员&#xff0c;科研工作者的喜爱。 …

主从模式详解

主从模式是分布式系统中&#xff0c;多个服务器部署redis的一种方式。分布式系统主要是解决“单点问题”。 如果某个服务器程序&#xff0c;只有一个节点&#xff08;只有一个物理服务器&#xff0c;来部署服务器程序&#xff09;。存在可用性问题&#xff0c;如果这个机器挂了…

1222. 可以攻击国王的皇后

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;从白国王出发方法二&#xff1a;从黑皇后出发 写在最后 Tag 【模拟】【数组】 题目来源 1222. 可以攻击国王的皇后 题目解读 在一个 8 8 8 \times 8 88 的棋盘上&#xff0c;有若干个「黑皇后」和一个「白国王」。…

[C语言]栈与队列——喵喵队,冲冲冲

宝子&#xff0c;你不点个赞吗&#xff1f;不评个论吗&#xff1f;不收个藏吗&#xff1f; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的很重要…

LeetCode刷题笔记【33】:动态规划专题-5(最后一块石头的重量 II、目标和、一和零)

文章目录 前置知识1049. 最后一块石头的重量 II题目描述解题思路代码 494. 目标和题目描述用回溯算法转换为背包问题动态规划 474.一和零题目描述解题思路代码 总结 前置知识 今天是动态规划专题的第5篇, 也是背包问题的第2篇. 所以本文和动态规划专题的1~3弱相关, 和上一篇, …

趣解设计模式之《小店儿菜单的故事》

〇、小故事 在一座小镇上&#xff0c;有两家特别有名气的小店&#xff0c;一家是远近闻名的早餐店&#xff0c;它家的早餐特别好吃&#xff0c;每天早上都能排起长长的队伍&#xff1b;另一家是个蛋糕店&#xff0c;他家是专门从法国请来的蛋糕师傅&#xff0c;蛋糕的香味真是…

uniapp微信小程序《隐私保护协议》弹窗处理流程

背景 《关于小程序隐私保护指引设置的公告》 《小程序隐私协议开发指南》 流程 1.第一步 必须设置且审核通过&#xff01;&#xff01;&#xff01; 2.第二步 uniapp在manifest.json中添加&#xff01;&#xff01;&#xff01; /* 在 2023年9月15号之前&#xff0c;在 ap…

汽车电子智能仓储系统的发展趋势与应用探索

现代汽车制造业中的仓储管理一直面临着多种挑战。仓库中物料的数量种类繁多&#xff0c;寻找物料耗时长、困难大。盘点过程耗费人力多、成本高、速度慢。管理无法达到先进先出的原则&#xff0c;也无法进行精准追溯。此外&#xff0c;多发、少发、错料等问题时有发生。仓库中的…

docker学习:dockerfile和docker-compose

学习如何使用dockerfile 以下内容&#xff0c;部分来自gpt生成&#xff0c;里面的描述可能会出现问题&#xff0c;但代码部分&#xff0c;我都会进行测试。 1. 需求 对于一个docker&#xff0c;例如python&#xff0c;我们需要其在构建成容器时&#xff0c;就有np。有以下两种方…

Linux内核源码分析 (B.x)Linux物理内存的初始化

Linux内核源码分析 (B.x)Linux物理内存的初始化 文章目录 Linux内核源码分析 (B.x)Linux物理内存的初始化一、DDR简介二、内存节点三、内存管理区域ZONE四、 struct zone五、 struct page六、mem_map数组七、伙伴系统简介八、迁移类型九、内存初始化十、总结 一、DDR简介 详细可…

电脑msvcp140.dll丢失问题的三种解决方法分享,快速修复dll问题

在我们的日常生活中&#xff0c;计算机已经成为了我们工作、学习和娱乐的重要工具。然而&#xff0c;在使用计算机的过程中&#xff0c;我们可能会遇到各种问题&#xff0c;其中之一就是 msvcp140.dll 丢失的困扰。本文将详细介绍 msvcp140.dll 丢失的原因、解决方法以及预防措…

可变参数JAVA

public class Main {public static void main(String[] args) {//方法形参的个数是可以变化的//格式&#xff1a;属性类型...名字System.out.println(getSum(1,2,3,4,5,6,7,8));}//通过键值对对象来遍历&#xff1b;public static int getSum(int a,int...args){//可变参数;int…

AirTag是什么?高精度测距定位防丢,UWB厘米级方案应用

随着科技的不断发展&#xff0c;超宽带&#xff08;UWB&#xff09;技术作为一种新兴的无线通信技术&#xff0c;逐渐受到人们的关注和追捧。 UWB技术以其传输速率高、抗干扰性强、带宽极宽、功耗低、安全性高、穿透力强、定位精准等优势&#xff0c;在众多领域具有广泛的应用…

输电线路故障数据集(基于simulink仿真批量生成故障数据,单相接地故障、两相接地故障、两相间短路故障、三相接地故障、三相间短路故障和正常)

分别获取单相接地故障、两相接地故障、两相间短路故障、三相接地故障、三相间短路故障和正常状态下的电流&#xff08;Ia,Ib,Ic&#xff09;大小和电压&#xff08;Ua,Ub和Uc&#xff09;大小。每种故障下获取1300行左右的数据 将故障区分为具体的不同类型&#xff08;一共五种…