Js几种循环方式的比较

前言:

循环的操作在代码中是必不可少的,本文将对Js中的for,while,forEach,for in,for of几种常用的循环进行对比及性能分析。
注意:本次对比的环境都是在浏览器端,并未测试node端的数据表现

正文:

1.for循环

for循环是自己控制循环过程,控制循环多少次。
我们来看看性能如何

    let arr=new Array(9999999).fill(0);//其他循环的arr测试用例也是这个

    console.time('for');
    for(let i=0;i<arr.length;i++){}
    console.timeEnd('for');

打开控制台,输出的是for: 6.1259765625 ms
(经过多次测试,时间都是在6s多)
在这里插入图片描述

2.while循环

while不知道循环次数,由条件语句控制。

    console.time('while');
    let i=0;
    while(i<arr.length){i++;}
    console.timeEnd('while');

打开控制台,输出的是while: 20.0771484375 ms
在这里插入图片描述

while与for对比

对比for循环发现,while循环的性能差了很多。
为什么会有这样的差异呢?
我们再把变量 i 的声明方式改成var来看看

    let arr=new Array(9999999).fill(0);

    console.time('for');
    for(var i=0;i<arr.length;i++){}
    console.timeEnd('for');

    console.time('while');
    var i=0;
    while(i<arr.length){i++;}
    console.timeEnd('while');

打开控制台,看输出结果,对比发现区别不大
在这里插入图片描述

原因:基于let声明的时候,for循环没有创造全局不释放的变量,for循环的时候会释放上一次循环的let 变量。var声明的变量都是全局变量

for(let i=0;i<arr.length;i++)
//创建的i是每次循环创建的块级作用域下面的,没有创造全局的,随着每轮循环结束释放
    
let i=0;
while(i<arr.length)//i在全局上下文中不被释放

我们可以得出结论:for跟while本身区别不大,但是
基于var声明的时候,for和while性能差不多
基于let声明的时候,for循环性能更好
一般情况下,如果我们明确知道循环多少次的话,用for循环,循环的次数需要条件判断的话就用while。

3.forEach循环

forEach是数组提供的遍历数组的方法

 	console.time('forEach');
    arr.forEach(function (item){})
    console.timeEnd('forEach');

在这里插入图片描述
可以看出,forEach明显比for和while都更慢。
因为是封装好的,内部也要处理其他逻辑,没有for和while那么清爽。用起来方便,好维护,但是我们无法管控过程,没办法中途终止循环,在性能上也有所消耗。
手写版forEach:

   Array.prototype.forEach = function forEach(callback, context) {
        //谁调用forEach,这里的this就是谁,所以这里是arr,用self保存起来,self[i]就表示每次循环的当前项
        let self = this,
            i = 0,
            len = self.length;
        //这里做个判断,forEach的第二个参数表示改变forEach的this值,也就是调用了call,如果没传第二个参数,默认是window
        context = context == null ? window : context;
        for (; i < len; i++) {
            typeof callback ===  "function" ? callback.call(context, self[i], i) : null;
        }
    }

    let arr = [1, 2, 3, 4]
    arr.forEach(function (item) {
        console.log(item);
    })

注意:forEach方法在数组元素为空时会跳过执行回调函数, 也就是forEach会忽略掉 [empty,…]

4.for in循环

    console.time('for in');
    for(let key in arr){}
    console.timeEnd('for in');

在这里插入图片描述
可以看出for in循环的性能是非常差的,这和for in本身的循环机制有关。

for in循环会迭代当前对象中所有可枚举的属性,其中私有属性大部分是可枚举的,查找机制上一定会搞到原型链上去,按原型链一级级查找很耗费性能。

另外,for in循环还有些小问题:
①遍历顺序以数字优先
②无法遍历Symbol属性
③可以遍历到公有中可枚举的

    Object.prototype.fn=function fn(){};
    let obj={
        name:'zhangSan',
        age:12,
        [Symbol('AA')]:100,
        0:100,
        1:200
    }
    for(let key in obj){
        console.log(key);
    }

控制台输出结果:
在这里插入图片描述

5.for of循环

    console.time('for of');
    for(let val of arr){}
    console.timeEnd('for of');

在这里插入图片描述

for of循环的原理是按照迭代器规范进行遍历。

  • iterator迭代器(ES6知识点),Symbol.iterator,具备next方法,每次执行返回一个对象,具备value/done属性。
  • 部分数据结构实现了迭代器规范,比如数组、某些类数组、Set、Map等等
  • 对象没有实现迭代器规范,所以对象不能用for of遍历

手动实现迭代器:

    let arr = [1, 2, 3, 4];
    arr[Symbol.iterator] = function () {
        let self = this,
            index = 0;
        return {
            //必须具备next方法,执行一次next方法,拿到结构中的某一项的值
            //done:false value:每一次获取的值
            next() {
                if (index > self.length - 1) {
                    return {
                        done: ture,
                        value: undefined
                    };
                }
                return {
                    done: false,
                    value: self[index++]
                };
            }
        };
    };

    console.time('for of');
    for (const val of arr) {
        console.log(val);
    }
    console.timeEnd('for of');

在这里插入图片描述

应用:对象默认不具备迭代器规范,如何让类数组对象具备呢?
我们来看看不具备迭代器的时候:

  let obj={
    0:100,
    1:200,
    2:300,
    length:3
   }
   for(let val of obj){
    console.log(val);
   }

在这里插入图片描述
加上迭代器:

   let obj={
    0:100,
    1:200,
    2:300,
    length:3
   }
   obj[Symbol.iterator]=Array.prototype[Symbol.iterator];
   for(let val of obj){
    console.log(val);
   }

在这里插入图片描述

以上就是Js几种循环方式的比较,感谢您的阅读,希望这篇文章能对你有所帮助,麻烦点赞收藏一下吧😋

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值