• 【JavaScript面试】数组的forEach()方法总结


    前言

    JavaScript数组的 forEach()方法总结。

    语法

    array.forEach(function(currentValue, index, arr), thisValue)
    
    • 1
    • currentValue (这是一个必须属性)表示当前元素
    • index (可选)表示当前元素的索引值
    • arr (可选)表示当前元素所属的数组对象
    • thisValue 这个是一个可选参数

    特点

    • 便利的时候更加简洁,效率和for循环相同,不用关心集合下标的问题,减少了出错的概率。
    • 没有返回值
    • 不能使用break中断循环,不能使用return返回到外层函数
    var arr = [1, 2, 3];
    var newarr=arr.forEach(function(curr, index, arr) {
                console.log(curr, index, arr)
          })
     console.log(newarr)
    输出结果:
    1 0 [1, 2, 3]
    2 1 [1, 2, 3]
    3 2 [1, 2, 3]
    undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    一般面试问题

    有了for循环,为什么还要forEach?

    这个问题的核心在于问for循环和forEach()的区别?我们可以从三个方面来回答这个问题。

    1. for循环和forEach的本质区别?

    forEach 其实是一个迭代器,他与 for 循环本质上的区别是 forEach 是负责遍历(Array Set Map)可迭代对象的,而 for 循环是一种循环机制,只是能通过它遍历出数组。
    forEach是ES5提出的,挂载在可迭代对象原型上的方法,例如Array Set Map。
    forEach是一个迭代器,负责遍历可迭代对象。
    (迭代器是一种特殊对象。ES6规范中它的标志是返回对象的next() 方法,迭代行为判断在done之中。在不暴露内部表示的情况下,迭代器实现了遍历。)

          //本质区别 forEach迭代器
            let arr = [1, 2, 3, 4] //可迭代对象
            let iterator = arr[Symbol.iterator]() //调用Symbol.iterator 后生成了迭代器对象
            console.log(iterator.next()); // {value: 1, done: false} 访问迭代器对象的next方法
            console.log(iterator.next()); // {value: 2, done: false}
            console.log(iterator.next()); // {value: 3, done: false}
            console.log(iterator.next()); // {value: 4, done: false}
            console.log(iterator.next()); // {value: undefined, done: true}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    2. for循环和forEach的语法区别?
    • 参数
    array.forEach(function(currentValue, index, arr), thisValue)
    
    • 1
     let arr2 = [1, 2, 3, 4];
            let person = {
                name: '技术直男'
            };
            arr2.forEach(function(self, index, arr) {
                console.log(`当前元素为${self}索引为${index},属于数组${arr}`);
                console.log(this.name += '---真帅');
            }, person)
            //当前的this指向的是person
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果为:
    在这里插入图片描述

    • for和forEach 的中断
      • 在js中有break return continue对函数进行中断或跳出循环的操作,
      • 我们在 for循环中会用到一 些中断行为,对于优化数组遍历查找是很好的
      • 但由于forEach属于迭代器, 只能按序依次遍历完成,所以不支持上述的中断行为。
            let arr3 = [1, 2, 3, 4];
            for (let i = 0; i < arr3.length; i++) {
                if (arr3[i] === 2) {
                    break;
                };
                console.log('for中断', arr3[i]);
            };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果是:
    在这里插入图片描述

    let arr3 = [1, 2, 3, 4];
    arr3.forEach((self, index) => {
                console.log('forEach中断', self);
                if (self === 2) {
                    // break; //报错
                    return; //会继续循环
                    // continue; //报错
                };
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    当其为break时结果报错,如下图:
    在这里插入图片描述

    当其为return时虽然没有报错,但是会继续循环,没有达到跳出循环的作用。如下图:
    在这里插入图片描述

    当其为continue时会报错,如下图:
    在这里插入图片描述

    那么问题来了:
    forEach不能使用break和continue这两个关键字,本身无法跳出循环,也不能像普通for循环一样使用return跳出,必须遍历所有的数据才能结束。
    我们如何跳出forEach中的循环呢?可以用try…catch…的方法

    try…catch…完整语法

    try {
        tryCode - 尝试执行的代码块
    }
    catch(error) {
        catchCode - 捕获错误的代码块
    }
    finally {
        finallyCode - 无论 try / catch 结果如何都会执行的代码块
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
      let arr3 = [1, 2, 3, 4];
            try {
                arr3.forEach(function(self, index) {
                    //跳出条件
                    if (self === 2) {
                        throw new Error("LoopTerminates");
                    }
                    //do something
                    console.log('forEach中断', self);
                });
            } catch (e) {
                if (e.message !== "LoopTerminates") throw e;
            };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
    达到了和for循环一样的效果。

    • forEach 删除自身元素,index不可被重置
      在forEach 中我们无法控制index 的值,它只会无脑的自增直至大于数组的length 跳出循环。所以也无法删除自身进行index
    let arr4 = [1, 2, 3, 4]
            arr4.forEach((item, index) => {
                // console. log(item); //1 2 3 4
                index++;
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    index不会随着函数体内部对它的增减而发生变化。在实际开发中,遍历数组同时删除某项的操作十分常见,在使用forEach删除时要注意。

    • forEach的循环起点只能为0不能进行人为干预,而for循环不同
    3. for循环和forEach的性能区别?
    • 性能比较: for > forEach > map
    • |在chrome 62和Node. js v9.1.0环境下:
      for循环比forEach 快1倍,forEach比map 快20%左右。
      原因分析for: for循环没有额外的函数调用栈和上下文,所以它的实现最为简单。
      forEach:对于forEach来说, 它的函数签名中包含了参数和上下文,所以性能会低于for 循环。
      map: map最慢的原因是因为map会返回一个新的数组,数组的创建和赋值会导致分配内存空间,因此会带来较大的性能开销。

    以上详细可以看链接

    for, forEach,for in,for of区别

    for in(大部分用于对象):
    用于循环遍历数组或对象属性

    特性:
    可以遍历数组的键名,遍历对象简洁方便

       let person={name:"小白",age:28,city:"北京"}
       let text=""
       for (let i in person){
          text+=person[i]
       }
       输出结果为:小白28北京
    //其次在尝试一些数组
       let arry=[1,2,3,4,5]
       for (let i in arry){
            console.log(arry[i])
        }
    //能输出出来,证明也是可以的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    for of(不能遍历对象):
    特性:

    1. (可遍历map,object,array,set string等)用来遍历数据,比如组中的值
    2. 避免了for in的所有缺点,可以使用break,continue和return,不仅支持数组的遍历,还可以遍历类似数组的对象。
       let arr=["nick","freddy","mike","james"];
        for (let item of arr){
            console.log(item)
        }
    //暑促结果为nice freddy mike james
    //遍历对象
       let person={name:"老王",age:23,city:"唐山"}
       for (let item of person){
            console.log(item)
        }
    //我们发现它是不可以的
    //但是它和forEach有个解决方法,结尾介绍
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总结:

    • forEach 遍历列表值,不能使用 break 语句或使用 return 语句
    • for in 遍历对象键值(key),或者数组下标,不推荐循环一个数组
    • for of 遍历列表值,允许遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等.在 ES6 中引入的 for of 循环,以替代 for in 和 forEach() ,并支持新的迭代协议。
    • for in循环出的是key,for of循环出的是value;
    • for of是ES6新引入的特性。修复了ES5的for in的不足;
    • for of不能循环普通的对象,需要通过和Object.keys()搭配使用。
  • 相关阅读:
    LeetCode - 哈希表专题
    模拟实现map/set[改编红黑树实现map/set容器底层]
    css画一条渐变的虚线
    [附源码]计算机毕业设计JAVA健身健康规划系统
    产品结构设计的主要内容有哪些?
    Linux多线程(线程的创建,等待,终止,分离)
    MATLAB神经网络编程(一)——感知器
    WPF应用框架中工作流模块的介绍
    Android 从Java线程到Handler机制源码分析
    SpringBoot如何配置拦截器呢?
  • 原文地址:https://blog.csdn.net/qq_40992225/article/details/126664328