数组遍历的几种方式

1. for循环

    // 最简单的一种循环遍历方法,也是使用频率最高的一种(可优化);循环过程中支持修改索引(修改 i)
        var arr = [1, 2, 3, 4, 5, 6]
        for(var i = 0; i < arr.length; i++) {
            console.log("普通for循环",arr[i])     //1 2 3 4 5 6
        }
    // 优化:使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显
        var arr = [1, 2, 3, 4, 5, 6]
        // var len = arr.length
        // for(var i = 0; i < len; i++) {
        //     console.log("优化后for循环",arr[i])     //1 2 3 4 5 6
        // }
        for(var i = 0,len=arr.length; i < len; i++) {
            console.log("优化后for循环",arr[i])     //1 2 3 4 5 6
        }
    // 能正确响应break、continue和return语句

2. for…in…

    // 这个循环效率比较低,适用于少量数据,也有不少人使用
        // 遍历数组,输出的 key 是数组索引
        var arr = ['我', '是', '谁', '我', '在', '哪']
        for(let key in arr) {
            console.log("for...in...遍历数组key",key)  // 0 1 2 3 4 5
            console.log("输出数组中key对应的值",arr[key])
        }
        // 遍历对象,输出的则是对象的属性名
        let obj = { a: 11, b: 22, c: 33 }
        for(let key in obj) {
            console.log("for...in...遍历对象key",key)  // a b c 
            console.log("输出对象中key对应的值",obj[key])
        }
    // 能正确响应break、continue和return语句

3. for…of…(ES6)

    // 虽然性能要好于 for..in...,但仍然比不上普通的 for 循环
    // 注意:不能循环对象,因为任何数据结构只要部署 Iterator接口,就可以完成遍历操作,有些数据结构原生具备 Iterator 接口,比如Array、Map、Set、String等,而 Iterator 接口是部署在数据结构的Symbol.iterator属性上的,而对象Object恰恰是没有Symbol.iterator属性的,所以无法被for..of遍历
        // 遍历数组,输出的 key 是数组元素值---不能循环对象
        var arr = ['我', '是', '谁', '我', '在', '哪']
        for(var key of arr) {
            console.log("for…of…遍历数组key",key)     // 我 是 谁 我 在 哪
        }
        // for-of遍历Map对象
        var  iterable =  new  Map([[ "a" , 1], [ "b" , 2], [ "c" , 3]]);
        for  ( let  [key, value] of iterable) {
            console.log("for-of遍历Map对象",value);     //输出 1 2 3
        }
        // for-of遍历字符串
        var  iterable =  "china中国" ;
        for  ( let  value of iterable) {
            console.log("for-of遍历字符串",value);     //输出 "c" "h" "i" "n" "a" "中" "国"
        }
    // 能正确响应break、continue和return语句

4. Object.keys()

// 上面的方法,注重点都是数组的元素或者对象的属性值。
// 如果单纯的想获取对象的属性名,js有原生的Object.keys()方法(低版本IE不兼容),返回一个由对象的可枚举属性名组成的数组:
    /****Object.keys()返回键名数组****/
        //数组类型
        var arr = [ "a" ,  "b" ,  "c" ];
        console.log(Object.keys(arr));  // (3) ['0', '1', '2']
        
        //类数组对象
        let  anObj = { 100:  'a' , 2:  'b' , 7:  'c'  };
        console.log(Object.keys(anObj));    // (3) ['2', '7', '100']
         
        //一般对象
        let  xyz = {z:  "zzz" , x:  "xxx" , y:  "yyy" };
        console.log(Object.keys(xyz));  // (3) ["z", "x", "y"]    
    
    // javascript原生遍历方法的建议用法:
        // 用for循环遍历数组
        // 用for-in遍历对象
        // 用for-of遍历类数组对象(ES6)
        // 用Object.keys()获取对象属性名的集合

5. forEach()–是JavaScript(ES5)的方法

    //  1. 数组里的元素个数有几个,该方法里的回调就会执行几次
    //  2. 第一个参数是数组里的元素,第二个参数为数组里元素的索引,第三个参数则是它自己(利用第三个参数可以进行数组去重)
        var arr = [1, 2, 3, 4, 5, 6]
        arr.forEach((item, index, array) => {
            console.log("forEach入参item",item)     // 1 2 3 4 5 6
            console.log("forEach入参index",index)     // 0 1 2 3 4 5 
            console.log("forEach入参array",array)    // [1, 2, 3, 4, 5, 6]
        })
    //  3. 数组自带的遍历方法,foreach在循环次数未知或者计算起来较复杂的情况下效率比for循环高
    //  4. 循环的数组元素是基本数据类型,不会改变原数据的数据;循环的数组元素为对象,会改变原数组的对象属性的值
        // 基本数据类型:undefined、null、Boolean、Number、String;
        // 复杂数据类型:Object(Object、Array、Function);
        // 循环的数组元素是基本数据类型,不会改变原数据的数据
        var arr1 = [1, 2, 3, 4, 5, 6]
        arr1.forEach((item) => {
            item = 10
        })
        console.log("循环数组元素是基本数据类型,不改变原数据",arr1) // [1, 2, 3, 4, 5, 6]

        // 循环的数组元素为对象,会改变原数组的对象属性的值
        var arr2 = [
            { a:1, b:2 },
            { a:11, b:12 }
        ]
        arr2.forEach((item) => {
            item.a = 10
        })
        console.log("循环数组元素为对象,改变原数组的对象属性值",arr2) // [{a: 10, b: 2}, {a: 10, b: 2}]
    //  5. 循环过程中不支持修改索引,回调中使用return不会报错,但是无效
    //  注意:不能使用break和continue跳出整个循环或当前循环的,会报错,但是结合try...catch可以实现跳出循环
        // 使用try...catch...可以跳出循环
        try {
            let arr = [1, 2, 3, 4];
            arr.forEach((item) => {
                // 跳出条件
                if (item === 3) {
                    throw new Error("LoopTerminates");
                }
                console.log("使用try...catch...跳出循环",item);   // 1 2
            });
        } catch (e) {
            if (e.message !== "LoopTerminates") throw e;
        };  

6. jQuery的each()

jQuery的$.each()
    // jQuery的遍历方法通常被用来遍历DOM元素,用于数组和对象的是$.each()方法,它接受三个参数,分别指代数组索引、元素、数组本身(跟forEach相比,第1个和第2个参数正好是相反的)
        // $.each()遍历数组
        var arrTmp=["我","爱","中","国"]
        $.each(arrTmp, function (index,value,array){
            console.log(index+ ": " +value)
        });
        // $.each()遍历对象
        var objTmp={a:'1',b:'2',c:'3'}
        $.each(objTmp, function (key,value){
            console.log(key+ ": " +value)
        });
        
jQuery的$().each()
    // $().each()是对页面元素的操作,此时可获取DOM元素直接操作
        var resourceInputVal = $("#ResouraceModal form input");
        $("#ResouraceModal .btn-default").click(function () {
            // button按钮的点击事件里可以直接修改input输入框的内容
            resourceInputVal.each(function (index, value) {
                // 注意index在前
                value.value = "";
            })
        })

7. map(ES6)

    //  遍历每一个元素并且返回对应的元素(可以返回处理后的元素) (map 映射 一一 对应)
    //  返回创建的新数组和原来旧数组的长度是一样的,使用比较广泛,但其性能还不如 forEach
    //  注意:不能使用break和continue跳出整个循环或当前循环的,会报错,但是结合try...catch可以实现跳出循环
        // 一、不会改变原数组
        var arr = [1, 2, 3, 4, 5, 6]
        var newArr = arr.map(function (item, index, arr) {
            console.log("map的callback函数的第三个参数",arr)
            return item * item
        })
        console.log("原数组1",arr)      // [1, 2, 3, 4, 5, 6]
        console.log("新数组1",newArr)   // [1, 4, 9, 16, 25, 36]

        // 二、不会改变原数组
        var arr2 = [{a: 1, b: 2},{a: 11, b: 12}]
        let newArr2 = arr2.map((item)=>{
            return {
                ...item,
                b:111
            }
        })
        console.log('原数组2',arr2) // [{a: 1, b: 2},{a: 11, b: 12}]
        console.log('新数组2',newArr2) // [{a: 1, b: 111},{a: 11, b: 111}]
        // 三、会改变原数组元素中对象的属性值
        var arr = [{a: 1, b: 2},{a: 11, b: 12}]
        let newARR = arr.map((item)=>{
            item.b = 111
            return item
        })
        console.log('arr数组',arr) // [{a: 1, b: 111},{a: 11, b: 111}]
        console.log('newARR',newARR) // [{a: 1, b: 111},{a: 11, b: 111}]

        // 四、使用try...catch...可以跳出循环
        try {
            var arr = [1, 2, 3, 4];
            arr.map((item) => {
                //跳出条件
                if (item === 3) {
                    throw new Error("LoopTerminates");
                }
                console.log("使用try...catch...跳出循环",item);  // 1 2
                // return item
            });
        } catch (e) {
            if (e.message !== "LoopTerminates") throw e;
        };

8. filter(ES6)

    // 遍历数组,过滤出符合条件的元素并返回一个新数组
    var arr = [
        { id: 1, name: '买笔', done: true },
        { id: 2, name: '买笔记本', done: true },
        { id: 3, name: '练字', done: false }
    ]   
    var newArr = arr.filter(function (item, index) {
        return item.done
    })
    console.log("filter遍历数组过滤",newArr)
    // [{ id: 1, name: '买笔', done: true },{ id: 2, name: '买笔记本', done: true }]

9. some(ES6)

    // 遍历数组,只要有一个以上的元素满足条件就返回 true,否则返回 false
    var arr = [
        { id: 1, name: '买笔', done: true },
        { id: 2, name: '买笔记本', done: true },
        { id: 3, name: '练字', done: false }
    ]
    var bool = arr.some(function (item, index) {
        return item.done
    })
    console.log("some返回值",bool)    // true

10. every(ES6)

    // 遍历数组,每一个元素都满足条件 则返回 true,否则返回 false
    var arr = [
        { id: 1, name: '买笔', done: true },
        { id: 2, name: '买笔记本', done: true },
        { id: 3, name: '练字', done: false }
    ]
    var bool = arr.every(function (item, index) {
        return item.done
    })
    console.log("every返回值",bool)    // false

11. find(ES6)

    // 遍历数组,返回符合条件的第一个元素,如果没有符合条件的元素则返回 undefined
    var arr = [1, 1, 2, 2, 3, 3, 4, 5, 6]        
    var num = arr.find(function (item, index) {
        return item === 3
    })
    console.log("find返回符合条件的第一个元素",num)   //  3

12. findIndex(ES6)

    // 遍历数组,返回符合条件的第一个元素的索引,如果没有符合条件的元素则返回 -1
    var arr = [1, 1, 2, 2, 3, 3, 4, 5, 6]       
    var num = arr.findIndex(function (item) {
        return item === 3
    })
    console.log("findIndex返回符合条件的第一个元素的索引",num)   //  4

13. reduce()

    // reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
        var total = [0,1,2,3,4].reduce((a, b)=>a + b); //10
        console.log("reduce()方法total",total)
    // reduce()接收一个函数,函数有四个参数,分别是:上一次的值,当前值,当前值的索引,数组
        var totalVal=[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array){
            console.log(previousValue,"+",currentValue,"=",(previousValue+currentValue))
            return previousValue + currentValue;
        });
        console.log("reduce()方法totalVal",totalVal)
    // reduce()还有第二个参数,我们可以把这个参数作为第一次调用callback时的第一个参数,上面这个例子因为没有第二个参数,所以直接从数组的第二项开始,如果我们给了第二个参数为5,那么结果就是这样的:
    // 第一次调用的previousValue的值就用传入的第二个参数代替,
        var SecParam=[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array){
            console.log(previousValue,"+",currentValue,"=",(previousValue+currentValue))
            return previousValue + currentValue;
        },5);
        console.log("reduce()方法SecParam",SecParam)

14. reduceRight()

    // reduceRight()方法的功能和reduce()功能是一样的,不同的是reduceRight()从数组的末尾向前将数组中的数组项做累加。
    // reduceRight()首次调用回调函数callbackfn时,prevValue 和 curValue 可以是两个值之一。如果调用 reduceRight() 时提供了 initialValue 参数,则 prevValue 等于 initialValue,curValue 等于数组中的最后一个值;如果没有提供 initialValue 参数,则 prevValue 等于数组最后一个值, curValue 等于数组中倒数第二个值。
        var arr = [0,1,2,3,4];
        var addArrValue=arr.reduceRight(function (preValue,curValue,index,array) {
            console.log(preValue,"+",curValue,"=","每次调的返回值:",(preValue+curValue))
            return preValue + curValue; 
        }); 
        console.log("reduceRight()方法addArrValue",addArrValue)     // 10
    // 如果提供一个初始值initialValue为5:
        var arr = [0,1,2,3,4];
        var initAddValue=arr.reduceRight(function (preValue,curValue,index,array) {
            console.log(preValue,"+",curValue,"=","每次调的返回值:",(preValue+curValue))
            return preValue + curValue;
        }, 5); 
        console.log("reduceRight()方法initAddValue",initAddValue)   // 15

15. keys()、values()、entries()

    // ES6 提供三个新的方法 —— keys()、values()和entries() —— 用于遍历数组。
    // 它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
    for (let index of ['a', 'b'].keys()) {
        console.log("keys()遍历键名",index);    // 0    // 1
    }
    
    for (let elem of ['a', 'b'].values()) {
        console.log("values()遍历键值",elem);   // 'a'  // 'b'
    }
    
    for (let [index, elem] of ['a', 'b'].entries()) {
        console.log("entries()遍历键值对", index, elem);   // 0 "a"     // 1 "b"
    }

关于跳出循环的几种方式
return =》结束循环并中断函数执行;
break =》结束循环函数继续执行;
continue =》跳过本次循环;
for 循环中的变量 i,由于ES5并没有块级作用域的存在,它在循环结束以后仍然存在于内存中,所以建议使用函数自执行的方式来避免;

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐