js面试——三大循环对比及性能分析

for循环及forEach底层原理

FOR循环是自己控制循环过程

  • 基于var声明的时候,FOR和WHILE性能差不多「不确定循环次数的情况下使用WHILE」

  • 基于let声明的时候,FOR循环性能更好「原理:没有创造全局不释放的变量」

  • for和while循环叫做命令式编程,数组的foreach/fiflter/some/every/等叫做函数式编程,是被别人封装好了的。

  • let arr = new Array(9999999).fill(0);
    
    console.time('FOR~~');
    for (let i = 0; i < arr.length; i++) {}
    console.timeEnd('FOR~~');
    
    console.time('WHILE~~');
    let i = 0; //while 声明了全局变量,占用内存空间
    while (i < arr.length) {
        i++;
    }
    console.timeEnd('WHILE~~');

console.time('FOREACH~~');
arr.forEach(function (item) {});
//arr.forEach((item)=>{console.log(item);})
console.timeEnd('FOREACH~~');
  • 手写forEach(callback,thisArg)
Array.prototype.forEach = function forEach(callback, context) {
    // this -> arr
    let self = this,
        i = 0,
        len = self.length;
    // 不传context this就是window。
    // 利用call(),指定callback的this、给callback传参。
    context = context == null ? window : context;
    for (; i < len; i++) {
        typeof callback === "function" ? callback.call(context, self[i], i) : null;
    }
};
  • forEach看它的底层机制,可以知道它比for循环和while循环的性能要差

for in循环的BUG及解决方案

  • for in性能很差:迭代当前对象中所有可枚举的属性

  •  迭代所有可枚举属性「私有&公有」,按照原型链一级级查找很耗性能

  • 问题很多:1、不能迭代Symbol属性;2、迭代顺序会以数字属性优先;3、公有可枚举的{一般是自定义属性}属性也会进行迭代。

  • 利用hasOwnProperty()的用法:继承的属性(公有属性)不显示。

  •  利用 getOwnPropertySymbols()方法获取数组的Symbol值,用concat()方法合并数组。
    ES5 引入了Object.keys方法,成员是参数对象自身的(不含继承的)所有可遍历属性的键名。

  • let obj = {
        name: 'zhufeng',
        age: 12,
        [Symbol('AA')]: 100,
        0: 200,
        1: 300
    };
    for (let key in obj) {
        if (!obj.hasOwnProperty(key)) break;
        console.log(key);
    }
    let keys = Object.keys(obj);
    if (typeof Symbol !== "undefined") keys = keys.concat(Object.getOwnPropertySymbols(obj));
    
    keys.forEach(key => {
        console.log('属性名:', key);
        console.log('属性值:', obj[key]);
    }); 

for of循环的底层机制

  • for of循环的原理是按照迭代器规范 (Symbol.iterator) 遍历的 迭代器协议
  • 迭代器iterator规范「具备next方法,每次执行返回一个对象,具备 value/done 属性」
  • 让对象(Object)具备可迭代性并且使用for of循环
  • // 类数组对象「默认不具备迭代器规范」
    let obj = {
        0: 200,
        1: 300,
        2: 400,
        length: 3
    };
    //给对象加一个Symbol.iterator,因为对象默认是不可迭代的
    obj[Symbol.iterator] = Array.prototype[Symbol.iterator];
    for (let val of obj) {
        console.log(val);
    } 
  • 手写for ..of..循环的底层
  • let arr = [10, 20, 30];
    //一个无参数的函数,其返回值为一个符合迭代器协议的对象。
    arr[Symbol.iterator] = function () {
        let self = this,
            index = 0;
        return {
            // 必须具备next方法,执行一次next方法,拿到结构中的某一项的值
            // done:false value:每一次获取的值
            next() {
                if (index > self.length - 1) {
                    return {
                        done: true,
                        value: undefined
                    };
                }
                return {
                    done: false,
                    value: self[index++]
                };
            }
        };
    };

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值