深入解析ES6中let和闭包

作者: a333661d6d6e | 来源:发表于2018-12-25 20:58 被阅读6次

    本篇文章主要介绍了深入理解ES6中let和闭包,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。

    本文介绍了深入理解ES6中let和闭包,分享给大家,具体如下:
    在开始本文之前我们先来看一段代码

    for(var i=0;i<10;i++){
      arr[i]=function(){
        return i;
      }
    }
    console.log(arr[3]());//10
    //欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
    

    显然这段代码输出10,并没有向我们期望的返回3,原因也很简单(js的变量提升)函数在调用时候访问的是一个全局作用域的i,此时for循环已经执行完毕,全局变量i=10;
    在ES5标准中,我们要想返回期望的3,通常的做法也很简单,就是让数组中的每个函数有单独的作用域,那么我们只要构造一个立即执行函数即可(js中没有块级作用域,只区分函数作用域和全局作用域)就像下面这样:

    var array=[];
    for(var i=0;i<10;i++){
      array[i]=(function(i){
      return function(){
        return i;
        }
      })(i);
    }
    console.log(array[3]());//3
    //欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
    

    这样一来数组的每个函数就处于一个立即执行函数的函数作用域中,该立即执行函数传入i,其实for循环执行了如下代码:

     array[0]=(function(i){
      return function(){
        return i;
        }
      })(0);
      array[1]=(function(i){
      return function(){
        return i;
        }
      })(1);
      array[2]=(function(i){
      return function(){
        return i;
        }
      })(2);
    //欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
    

    这样一来,数字组中每个函数对应一个单独的函数作用域(立即执行函数的)这里共创建了10个函数作用域,这些函数作用域里的i值就是执行时候传入的0……9,当执行
    array3;时候函数访问的i值是其对应的立即执行函数作用域里的 i,而不是全局的i值,这样我们就得到了预期的效果。
    说得到这里我们简单来说一下闭包,闭包可以理解为一个闭包就是一个没有释放资源的栈区,栈区内的变量处于激活状态。上面的例子中for循环在执行时系统分配内存,js执行线程创建执行栈区,执行时候检测到立即执行函数里的变量i被内部函数引用,所以该栈区在内存中没有被释放,函数(数组元素)被调用时候根据作用链首先访问到的是上一级作用域(立即执行函数)的变量。
    这里不再详细介绍闭包,如果想详细了解闭包请阅读《javascript高级程序设计》第7章
    前面提到js中并没有块级作用域,只区分全局作用域和函数作用域,在ES6中let实际是为js新增了块级作用域,例如下面代码不用创造函数作用域就可以让每个数组里的函数访问各自作用域里的值:

    let arr=[];
    for(let i=0;i<10;i++){
      arr[i]=function(){
        return i;
      }
    }
    console.log(arr[3]());//3
    //欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
    

    可以看到我们并没有像之前那样构造一个函数作用域就能实现我们期望的效果,引入块级作用域之后更方便我们书写和理解代码,上述代码中for循环之后的{}是块级作用域,每次循环时候每个返回的函数引用的是其对应块作用域的变量,稍微改一下代码看着形象些:

    let arr=[];
    for(let i=0;i<10;i++){
      let k=i;
      arr[k]=function(){
        return k;
      }
    }
    console.log(arr[3]());//3
    //欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
    

    可见ES6引入块作用域之后我们构造闭包函数更方便了。
    这里不多叙述let和const的相关内容,如果之前没接触ES6的小伙伴建议阅读阮一峰老师的《ES6标准入门》。
    在这里再提一点,很多人看完概念之后,第一印象都是:“const 是表示不可变的值,而 let 则是用来替换原来的 var 的。”很多时候把let当做是var的替代品,凡是声明变量就用let,你很可能写出下面代码:

    // 定义常量
    const REG_GET_INPUT = /^\d{1,3}$/; 
    // 定义配置项
    let config = {
     isDev : false,
     pubDir: './admin/'
    } 
    let path = require('path');
    let HtmlWebpackPlugin = require('html-webpack-plugin');
    let CleanWebpackPlugin = require('clean-webpack-plugin');
    //欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
    

    const 的定义是不可重新赋值的值,与不可变的值(immutable value)不同;const 定义的 Object,在定义之后仍可以修改其属性。
    所以其实他的使用场景很广,包括常量、配置项以及引用的组件、定义的 “大部分” 中间变量等,都应该以cosnt做定义。反之就 let 而言,他的使用场景应该是相对较少的,我们只会在 loop(for,while 循环)及少量必须重定义的变量上用到他。
    猜想:就执行效率而言,const 由于不可以重新赋值的特性,所以可以做更多语法静态分析方面的优化,从而有更高的执行效率。

    结语

    感谢您的观看,如有不足之处,欢迎批评指正。

    本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
    对web开发技术感兴趣的同学,欢迎加入Q群:864305860,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
    最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

    相关文章

      网友评论

        本文标题:深入解析ES6中let和闭包

        本文链接:https://www.haomeiwen.com/subject/dikzkqtx.html