• JS中for...in循环陷阱及遍历数组的方式对比


    JavaScript中有很多遍历数组的方式,比较常见的是for(var i=0;i<arr.length;i++){},以及for...in...循环等,这些遍历都有各自的优缺点,下面来看看各种JS的遍历对比:

    1.for...in...

    1).index索引为字符串型数字,不能直接进行几何运算。

    2).遍历顺序有可能不是按照实际数组的内部顺序。

    3).使用for in会遍历数组所有的可枚举属性,包括原型。例如上栗的原型方法method和name属性。

    Array.prototype.myfun=function(){
        alert('myfun');
    }    
    var arr = [0,1,2,3];
    
    for(var i in arr){
        console.log(arr[i]);
    }
    
    console.log(Array.prototype)

     运行结果:

    上面的例子很好的反映了for...in...循环的缺点,原本只想循环取出该数组的数据,但是由于之前给数组添加了原型函数,导致循环的结果多了一个函数。这种场景我在使用lodop打印控件写打印功能时遇到过,打印的内容我用for...in...循环打印了,结果打印的结果莫名其妙多了一串代码,排查了很久才发现原来是lodop.js将Array数组的原型添加了方法,导致循环的时候将该方法也遍历到了,所以for...in...循环最好使用在遍历对象上,不要用来遍历数组。

    2.普通for循环

    let arr = [1,2,3,4,5]; 
    
    for (var index = 0; index < arr.length; index++) {
     console.log(arr[index]); 
    }

    这是最原始的写法,也是应用比较多的循环方式,但写法较为麻烦,性能有优化空间。

    3.优化for循环

    var arr = [0,1,2,3];
    
    for(j=0,len=arr.length;j<len;j++){
        console.log(arr[j]);
    }

    使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显。这种方法基本上是所有循环遍历方法中性能最高的一种,所以推荐使用这种循环。

    4.forEach循环

    let arr = [1,2,3,4,5]; 
    arr.forEach((element,index) => { 
        console.log(element); 
    });

    forEach循环是数组自带的方法,这种方式循环十分方便,不需要获取数组长度即可循环,但是有一个问题,在循环的中途无法跳出forEach循环,break命令或return命令都不能奏效,也就是说一循环必然会执行完毕,不能灵活运用于多种情况。

    5.for...of...循环

    for…of是ES6新增的遍历方式,它提供了统一的遍历机制。所有实现了[Symbol.iterator]接口的对象都可以被遍历。for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、Generator 对象,以及字符串。

    优点:

    • 有着同for...in一样的简洁语法,但是没有for...in那些缺点
    • 不同用于forEach方法,它可以与breakcontinuereturn配合使用
    • 提供了遍历所有数据结构的统一操作接口

    下面是一个使用break语句,跳出for...of循环的例子。

    for (var n of arr) {
     if (n > 2) break;console.log(n); 
    }

    上面的例子,会输出斐波纳契数列小于等于2的项。如果当前项大于2,就会使用break语句跳出for...of循环。

    for...of获取索引
    • entries返回一个遍历器对象,用来遍历[键名, 键值]组成的数组。对于数组,键名就是索引值;对于 Set,键名与键值相同。Map 结构的 Iterator 接口,默认就是调用entries方法。
    • keys返回一个遍历器对象,用来遍历所有的键名。
    • values返回一个遍历器对象,用来遍历所有的键值。
    let arr = ['a', 'b', 'c']; 
    for (let pair of arr.entries) { 
    console.log(pair); 
    } // [0, 'a'] // [1, 'b'] // [2, 'c']
    类似数组的对象

    类似数组的对象包括好几类。下面是for...of循环用于字符串、DOM NodeList 对象、arguments对象的例子。

    // 字符串 
    let str = "hello"; 
    for (let s of str) {
     console.log(s); // h e l l o 
    } // DOM NodeList对象 
    let paras = document.querySelectorAll("p");
    for (let p of paras) { 
        p.classList.add("test"); 
    } // arguments对象 
    function printArgs { 
        for (let x of arguments) { 
            console.log(x); 
        } 
    } 
    printArgs('a', 'b'); // 'a' // 'b'

    并不是所有类似数组的对象都具有 Iterator 接口,一个简便的解决方法,就是使用Array.from方法将其转为数组。

    let arrayLike = { 
        length: 2, 
        0: 'a', 
        1: 'b' 
    }; 
    // 报错
    for (let x of arrayLike) { 
       console.log(x); 
    } 
    // 正确 
    for (let x of Array.from(arrayLike)) { 
      console.log(x); // 'a' // 'b'
    }
    普通的对象

    对于普通的对象,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。

    let es6 = { 
        edition: 6, 
        committee: "TC39", 
        standard: "ECMA-262" 
    }; 
    for (let e in es6) { 
        console.log(e); 
    } // edition // committee // standard 
    for (let e of es6) {
        console.log(e); 
    } // TypeError: es6 is not iterable

    解决方法是,使用Object.keys方法将对象的键名生成一个数组,然后遍历这个数组。

    let es6 = { 
        edition: 6, 
        committee: "TC39", 
        standard: "ECMA-262" 
    };
    for (var key of Object.keys(es6)) { 
        console.log(key + ': ' + es6[key]); 
    }
  • 相关阅读:
    JAVA-throw new IOException报错unhandled exception:java.lang.Exception 2021年6月7日
    GIt保持远程 源仓库与Fork仓库同步--2017年6月13日
    Python的getattr()-2017年6月7日
    JavaScript学习-2017年5月18日
    Writing your first Django app--2017年5月9日
    M4-AC6 Oh,Trojan Again--2017年5月9日
    吴军硅谷来信
    【1】Prologue--A Game of Thrones--2017年4月8日
    M4-PC9 Read 10,000 Books,Travel 10,000 Miles--2017年5月8日
    资源分配图RAG的化简
  • 原文地址:https://www.cnblogs.com/wangxiayun/p/10194806.html
Copyright © 2020-2023  润新知