js闭包概念介绍

写这份博客的原因是在某个充满活力的早晨被某人的画法houyhea所吸引,学习了一下之前不是很懂的闭包概念。

本篇博客以引文为主,请大家记得给原作者点赞

根据《JavaScript权威指南》里对于闭包的解释

所有的JavaScript函数都是闭包,而当一个嵌套函数被导出到定义它的作用域外时,会发生很有趣(蛋疼)的事情

阮一峰的理解

闭包可以简单理解为定义在一个函数内部的函数,然后可以通过返回这个函数访问到定义它的函数的局部变量。闭包就是能够读取其他函数内部变量的函数。

比如说

1
2
3
4
5
6
7
8
9
  function f1(){
    var n=999;
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999

这个例子里面f2就是一个闭包,因为f2在f1中定义,并且可以读取f1的局部变量。

闭包除了能够读取函数的内部变量外,还能够让这些变量驻留在内存中。例如以下这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
  function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

可见函数f1的局部变量n在f1调用结束之后并没有被清除。因为f2依赖于f1,而f2被赋给了一个全局变量result,所以f2不会被销毁,于是f1也不能被销毁,于是n也就留下来了。这个例子中的nAdd是一个全局变量,因为没有加上var,原因可参见阮一峰的博客,在参考文献中给出。

这里,我有一个疑问,如果闭包被赋予的是一个局部变量,那么还会发生内存驻留的问题吗?还是说这种情况本身就不存在。请大神指点。

最后放上一张用尽目前绘画能力的闭包示意图,请各位指点

package

外面的框子可以理解成一个函数,a是这个函数中的局部变量。正常情况下是不能从函数外部访问a的,所以需要一个钩子将a勾出来。这个钩子的底就是fn,也就是声明在同一个函数内部的函数,代码示例如下:

1
2
3
4
5
6
7
  function f(){
    var a=999;
    function fn(){
      alert(n);
    }
    return fn;
  }

通过return fn将闭包传递出去,然后外部就可以通过这个返回值,访问内部的变量,就像拿住了钩子的柄,勾出了东西。

闭包虽好,但是不要乱用,js的gc目前还伤不起

参考文献

  1. 一张图搞定闭包概念
  2. javascript权威指南
  3. 阮一峰:学习Javascript闭包(Closure)