关于闭包

99 阅读2分钟

一,什么是闭包?

在《你不知道的JavaScript》一书中是这样描述的:当函数可以记住并访问所在的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。

二,闭包的用途是什么?

 1、读取函数内部的变量。
 2、让这些变量的值始终保持在内存中。不会再因为调用后被垃圾回收自动清除。
 3、方便调用上下文的局部变量,利于代码封装。

例如:for循环中使用定时器延迟打印的问题

     for (var i = 1; i <= 10; i++) {
      setTimeout(function () {
		console.log(i);
	  }, 1000);
     }

在这段代码中,我们对其的预期是输出1~10,但却输出10次11。这是因为setTimeout中的匿名函数执行的时候,for循环都已经结束了,for循环结束的条件是i大于10,所以会输出10次11。 原因:i是声明在全局作用中的,定时器中的匿名函数也是执行在全局作用域中,所以每次都输出11。 原因知道了,解决起来就简单了,我们可以让i在每次迭代的时候,都产生一个私有的作用域,在这个私有的作用域中保存当前i的值。

     for (var i = 1; i <= 10; i++) {
	    (function () {
		        var j = i;
		setTimeout(function () {
			console.log(j);
		}, 1000);
	   })();
    }

这样就达到我们的预期了,让我们用一种比较优雅的写法改造一下,将每次迭代的i作为实参传递给自执行函数,自执行函数中用变量去接收:

      for (var i = 1; i <= 10; i++) {
	           (function (j) {
		    setTimeout(function () {
			console.log(j);
	  	  }, 1000);
	      })(i);
      }

三,闭包的缺点是什么?

1,闭包会驻留在内存中,会增大内存使用量,使用不当很容易造成内存泄露,降低程序的性能,但是这并不是闭包本身的错误造成的,而是由于我们自己使用不当。更重要的是,对闭包的使用不当会造成无效内存的产生 解决方法是,在退出函数之前,将不使用的局部变量全部删除。

例子:

      function  showId() {
        var el = document.getElementById("app")
           el.onclick = function(){
      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
      }
    }

     // 改成下面
      function  showId() {
        var el = document.getElementById("app")
        var id  = el.id
      el.onclick = function(){
           aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
          }
           el = null    // 主动释放el
      }

2,闭包会在父函数外部,改变父函数内部变量的值。

举例

         function fun(){
               var a=12; //这是变量a的值是12.
           function fun1(){
                  return ++a;
             }
                return fun1;
         }
            var a=fun();
        a();//这个时候变量a的值是13了;
        a();//这个时候变量a的值是14了;
        a();//这个时候变量a的值是15了;