zoukankan      html  css  js  c++  java
  • JS闭包

    闭包

    什么是闭包

    • 函数执行形成一个私有的作用域,保护里面的私有变量不受外界的干扰,这种保护机制称之为“闭包”
    • 开发者普遍认为的闭包是:形成一个不销毁的私有作用域(私有栈内存)才是闭包

    闭包的2种写法

    闭包:柯理化函数

    function fn(){
        return function(){};
    }
    var f = fn();
    

    闭包:惰性函数

    var utils = (function(){
        return {};
    })();
    

    闭包的实际应用

    真实项目中为了保证JS的性能(堆栈内存的性能优化),应该尽可能的减少闭包的使用(不销毁的堆栈内存是耗性能的)

    1. 闭包具有保护作用:保护私有变量不受外界的干扰
      在真实项目中,尤其是团队协作开发的时候,应当尽可能的减少全局变量的使用,以防止相互之间的冲突(“全局变量污染”),那么此时我们完全可以把自己这一部分内容封装到一个闭包中,让全局变量转换为私有变量。
    (function(){
        var n = 12;
        function fn(){
        }
    })();
    

    不仅如此,封装类插件的时候,也会把程序都存放到闭包中保护起来,防止和用户的程序冲突,但是又需要暴露一些方法给客户使用,这样我们如何处理?

    • JQ这种方法:把需要暴露的方法抛到全局
    (function (){
        function jQuery() {
            console.log(1);
        }
        window.jQuery = window.$ = jQuery;
    })();
    jQuery();
    $();
    
    • Zepto这种方式:基于RETURN把需要共外面使用的方法暴露出去
    var Zepto = (function (){
        return {
            xxx: function (){
            console.log(1);}
        };
    })();
    Zepto.xxx();
    
    1. 闭包具有保存作用:形成不销毁的栈内存,把一些值保存下来,方便后面的调取使用
    function changeTab(n) {
        console.log(n);
      }
      let tabList = [{}, {}, {}];
      for (var i = 0; i < tabList.length; i++) {
        tabList[i].onclick = (function (i) {
          // 让自执行函数执行,把执行的返回值(return)赋值给ON-CLICK(此处ON-CLICK绑定的是返回的小函数,
          //      点击的时候执行的是小函数),自执行函数在给事件赋值的时候就已经执行了
          return function () {
            changeTab(++i); // 上级作用域:自执行函数形成的作用域
          };
        })(i);
      }
      for (var i = 0; i < tabList.length; i++) {
        console.log(tabList[i]);
        tabList[i].onclick();
      }
      /**
       * 循环三次,形成3个不销毁的私有作用域(自执行函数执行),而每一个不销毁的栈内存中都存储了一个私有变量,而这个值分别是每一次执行传递进来的全局i的值(也就是:第一个不销毁的作用域存储的是0,第二个是1,第三个是2):
       * 当触发点击事件,执行返回的小函数,遇到变量I,向它自己的上级作用域查找,找到的I值分别是:0/1/2,达到了我们想要的效果
       */
      for (var i = 0; i < tabList.length; i++) {
        console.log(tabList[i]);
        tabList[i].onclick();
      }
    
    

    这样非常损耗性能
    其他写法,相同效果

    for (var i = 0; i < tabList.length; i++) {
        (function (i) {
          tabList[i].onclick = function () {
            changeTab(++i);
          };
        })(i);
    }
    

    基于ES6中的LET来创建变量,是存在块级作用域的(类似于私有作用域)

    for (let i = 0; i < tabList.length; i++) {
        tabList[i].onclick = function () {
          changeTab(++i);
        };
    }
    

    判断体、循环体也都是块级作用域,初始值设置的变量是当前本次块级作用域中的变量,循环几次就有几个块级作用域

    {
        let a = 5;
        console.log(a);
    }
    console.log(a); // a is not defined
    
  • 相关阅读:
    git 获取之前某个版本
    mysql默认查询顺序
    tp5链式查询fetchSql(true)方法
    微信中关闭网页输入内容时的安全提示
    SourceTree + BeyondCompare 配置 + 使用教程
    SourceTree 免登录跳过初始设置
    git 常规发布流程
    Git常用操作命令
    手动安装phpRedisAdmin
    docker-compose快速搭建lnmp+redis服务器环境
  • 原文地址:https://www.cnblogs.com/xiaoxu-xmy/p/13639380.html
Copyright © 2011-2022 走看看