• JavaScript中数组中遍历的方法


    前言

    最近看了好几篇总结数组中遍历方法的文章,然而“纸上得来终觉浅”,决定此事自己干。于是小小总结,算是自己练手了。

    各种数组遍历方法

    数组中常用的遍历方法有四种,分别是:

    • for
    • for-in
    • forEach
    • for-of (ES6)

    for

    使用for循环来遍历一个数组,代码如下:

    // for循环
        let arr=[2,4,6,10];
        for(let i=0;i<arr.length;i++){
            console.log(arr[i]);
        }
    

    当数组的长度不回改变时,我们使用一个变量来存储数组的长度arr.length,以获得更好的效率(因为每次比较的时候都省去计算arr.length)。改进后的算法如下:

     // for循环
        let arr=[2,4,6,10];
        for(let i=0,len=arr.length;i<len;i++){
            console.log(arr[i]);
        }
    

    当然如果不考虑输出顺序,为了简化,也可以使用i--,代码如下:

     // for循环
    	let arr=[2,4,6,10];
        for(let i=arr.length;i>=0;i--){
            console.log(arr[i]);
        }
    

    for-in

    通常情况下,我们可以这样使用:

     //for-in 循环
        let arr=[2,4,6,10];
        let index;
        for (index in arr){
            console.log(arr[index]);
        }
    

    输出结果

    	arr[0]=2
        arr[1]=4
        arr[2]=6
        arr[3]=10
    

    来,我们再看一个例子:

    	//for-in 循环
        let per={
            name:"zhang San",
            sex:'male',
            age:18
        };
        for(let key in per){
            console.log("per[" + key + "]=" + per[key]);
        }
    

    输出结果

    	per[name]=zhang San
    	per[sex]=male
    	per[age]=18
    

    根据上面的两个例子可以看到,for-in不仅可以遍历数组还可以遍历对象
    注意:文章深入了解 JavaScript 中的 for 循环 指出for-in 遍历属性的顺序并不确定,即输出的结果顺序与属性在对象中的顺序无关,也与属性的字母顺序无关,与其他任何顺序也无关。,但是我在实际操作中,发现输出一直是上面的结果,即其按照了定义属性的顺序输出了。

    此时,我们回头再次看一个for-in的例子:

    	Array.prototype.fatherName = "Father";
    	let arr=[2,4,6,10];
        arr.name="hello,world!";
        let index;
        for (index in arr){
            console.log('arr['+index+']='+arr[index]);
        }
    

    输出结果

    	arr[0]=2
        arr[1]=4
        arr[2]=6
        arr[3]=10
        arr[name]=hello,world!
        arr[Father]=Father
    

    我们发现一个问题,使用for-in在遍历的时候,它不仅遍历了对象上的属性,而且还遍历了对象父类原型上的属性。
    所以for-in并不适合遍历Array中的元素,更适合遍历对象中的属性,这也是创造for-in的初衷。但是对于稀疏数组,使用它却是极好的。例子如下:

    let key;
    let arr = [];
    arr[0] = "a";
    arr[999] = "b";
    arr[99999] = "c";
    for(key in arr) {
    	if(arr.hasOwnProperty(key)  && /^0$|^[1-9]d*$/.test(key) && key <= 100000) {
            console.log(arr[key]);
        }
    }
    

    在上面的例子当中,由于for-in只会遍历存在的实体,因此使用for-in循环,只需要遍历3次,而使用for循环则需要遍历100000次。

    for-in的性能

    由于使用它的时候,每次需要遍历对象中存在的实体,以及对应的原型链上的属性。因此其速度相比较其他for循环,要慢一些。所以除非明确要迭代一个属性数量未知的对象,否则应该避免使用for-in

    forEach

    forEach()方法为数组中的每一个有效元素执行一次callback函数。遍历数组让数组中的每一个元素做一件事情。那些已经被删除(使用delete方法等情况)或者未初始化的项将被跳过(但不包含那些值未undefined的项目)。
    注意,callback函数将依次被传入3个参数:

    • 数组当前项的值
    • 数组当前项的索引
    • 数组对象本身

    看个例子:

    	let arr = [];
        arr[0] = "a";
        arr[3] = "b";
        arr[10] = "c";
        arr[name] = "Hello world";
        arr.forEach((data, index, array) => {
            console.log(data, index, array);
        });
    

    输出结果

    a 0 ["a", 3: "b", 10: "c", name: "Hello world"]
    b 3 ["a", 3: "b", 10: "c", name: "Hello world"]
    c 10 ["a", 3: "b", 10: "c", name: "Hello world"]
    

    值得注意的是:

    • 没有输出name。why? 因为name是arr的属性,而0,3,10都是arr的索引。
    • 这里的 index 是 Number 类型,并且也不会像 for-in 一样遍历原型链上的属性。

    forEach的性能

    在不同浏览器下测试的结果都是 forEach 的速度不如 for。可以看到forEach主要应用在遍历数组,但是它的性能并不如for,因此可以使用for就尽量不要使用forEach。

    for-of(ES6中新增)

    for-of是ES6中新增的一个遍历数组或者类数组的方法。它的出现主要是为了解决ES5中3种遍历方式的缺陷:

    • forEach 不能break 或者return
    • for-in 的缺点更加明显。它不仅遍历了数组中的元素,还遍历了自定义属性,甚至连原型链上的属性都被访问到。

    因此使用for-of的优势在于:

    • 这是最简洁、直接遍历数组的方式
    • 这个方法避开了for-in循环的缺陷
    • 与forEach不同,它可以正确响应break,continue,return 语句。

    说了这么多for-of的优点,那么它有没有缺点呢?

    for-of不支持普通对象遍历,如果想要遍历普通对象,使用for-in

    例子:

    	let arr=[3,7,9];
        for (let key of arr){
            console.log(key);
        }
    

    结果

    3
    7
    9
    

    性能

    由于for-of也是只遍历可迭代对象的数据,相比于for-in,效率会更高。

    Other 循环方法

    说明:下面的方法,Map,Reduce,Filter,Every,some方法都是面向数组的。不是普通对象。

    map(不改变原数组)

    map方法(映射)给数组中的每个元素执行一次callback函数,执行callback函数的返回值组成一个新数组。未被初始化项、已经被删除项(使用delete等方法)、数组的属性不会被执行callback函数。
    请看如下例子:

    	let arr=new Array(5);
        arr[1]=1;
        arr[2]=2;
        arr.name="hello,world!";
        delete(arr[2]);
    
        let fireArr=arr.map(item=>item*5);
        console.log(fireArr);
    

    输出结果:

    [empty,5,empty,empty,empty]
    

    reduce

    reduce方法,让数组的前项后项进行某种计算。累计最终的结果。
    例子:

    	//reduce方法
        let arr = [4,7,8,3];
        let total= arr.reduce( function (x, y) {
            console.log(x);
            return x + y;
    
        });
        console.log(total);
    

    输出结果

       4 
       11
       19
       22
    

    filter(不改变原数组)

    filter的意思是滤镜、过滤器,顾名思义就是用来筛选符合某种条件的元素,将符合条件的元素重新组成一个新的数组。
    还是看一个例子:

    	let arr = [2,3,4,5,6];
        arr.name=8;
        let morearr = arr.filter(function (number) {
            return number > 3
        });
        console.log(morearr);
    

    输出结果

        4, 5, 6
    

    在上面的例子中,将大于索引大于3的元素输出。而不会输出属性。

    every

    every方法为数组中的每个元素执行一次 callback 函数,当它找到一个使 callback 返回 false(表示可转换为布尔值 false 的值)的元素,就立刻返回false。否则,callback为每个元素返回true,every就返回true。
    看一面的例子

    	let arr = [1,2,3,4,5];
        let result = arr.every(function (item, index) {
            return item > 0
        });
        console.log(result);
    

    返回结果

    	true
    

    some

    some 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some 将会立即返回 true。否则,some 返回 false。

    	let arr = [1,2,3,4,5];
        let result = arr.some(function (item,index) {
            return item > 3
        });
        console.log(result);
    

    iterator

    最后,还有一个东西不得不介绍,ES6新增的iterator,迭代器。
    看例子:

    const arr = ['a', 'b', 'c'];
    const iter = arr[Symbol.iterator]();
    
    iter.next() // { value: 'a', done: false }
    iter.next() // { value: 'b', done: false }
    iter.next() // { value: 'c', done: false }
    iter.next() // { value: undefined, done: true }
    

    iterator名叫“迭代器”,iter.next()实际上是探测下一个位置是否有数据的探测器,如果有就返回false;如果下一个位置上没有,就返回true。

    效率问题

    1、循环效率

    	for > for-of > forEach > filter > map > for-in
    

    可以看到 的是for循环的速度是最快的,是最老的循环方法,也是优化得最好的;其次是for-of这个是es6才新增的循环非常好用,最慢是for-in,原因是它遍历了原型链上的属性。

    2、some 和 every

    他们都是根据判断条件,返回给整个数组Boolean 值的方法,every 的执行速度会比some快很多。

    • every是不满足判断条件后,立即返回“假的”false值给整个数组。否则继续执行,返回true。
    • some是满足判断条件后,立刻返回“真值”true给整个数组。否则继续执行,返回false。

    参考文档:
    JavaScript 数组遍历方法的对比
    深入了解 JavaScript 中的 for 循环

  • 相关阅读:
    2019杭电多校训练(一)
    2019牛客多校训练(二)
    2019牛客多校训练(一)
    codeforces#1196F. K-th Path(最短路,思维题)
    codeforces#1108E2. Array and Segments (线段树+扫描线)
    codeforces#1183F. Topforces Strikes Back(数论)
    SPOJ
    2020年4月 第十一届蓝桥杯大赛个人赛(软件类)省级模拟赛
    Codeforces Round #634 (Div. 3)
    POJ
  • 原文地址:https://www.cnblogs.com/QuietWinter/p/9115855.html
Copyright © 2020-2023  润新知