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
posted @ 2020-09-09 15:57  lemon-Xu  阅读(121)  评论(0编辑  收藏  举报