1、什么是闭包?

闭包就是指有权访问另一个函数作用域中变量的函数,通俗点讲闭包就是能够读取其他函数变量的函数。常见的构造方法,是在一个函数内部定义另外一个函数。内部函数可以引用外层的参数和变量;参数和变量不会被垃圾回收机制回收。除非用立即执行函数来解决。所以闭包的特性:

(1)函数内再嵌套函数;

(2)内部函数可以引用外层的参数和变量;

(3)参数和变量不会被垃圾回收机制回收。

复制代码
 1         function fn1() {
 2             var a = 1 ;
 3             function fn2() {
 4                 alert(a);
 5             }
 6             return fn2;
 7         }
 8 
 9         var result = fn1();
10         result();  //1
复制代码

上述函数fn2就是一个闭包,我们可以通过返回fn2获取到fn1中的变量。

2、闭包的用途

(1)通过闭包去访问函数内部的变量;

(2)使某些变量常驻内存。

复制代码
 1         //没有闭包情况下变量a的情况
 2         function add() {
 3             var a = 1;
 4             a++;
 5             alert(a);
 6         }
 7         add();   //2
 8         add();   //2
 9 
10         //有闭包的方式下
11         function add2() {
12             var a = 1;
13             function fn() {
14                 a++;
15                 alert(a);
16             }
17             return fn;
18         }
19         var result = add2();
20         result();  //2
21         result();  //3
复制代码

在有闭包的情况下,result()的两次输出分别是2、3,这说明aad2中的a变量一直在内存当中,并没有因为add2的调用后被垃圾回收机制回收(garbage collection)。

为什么会产生这样的情况?这是因为add2是fn的父亲函数,而在全局环境当中,fn其实是被赋给了全局变量result的,而result只会在全局环境执行完所有代码之后才会被回收,所以就导致了fn常驻内存,而fn的存在又依赖于父亲函数add2,所以add2在被调用之后也不会被GC(垃圾回收机制)回收,也始终存在于内存当中。

3、闭包可能会引发的问题

由于IE9之前的版本对JSript对象和COM对象使用了不同的垃圾回收机制,所以闭包在IE9之前的版本中会导致内存泄漏问题。具体来说就是,如果闭包中保存着一个HTML元素,那么这个元素将无法被销毁,直到退出程序或关闭浏览器。

复制代码
1     <script>
2         window.onload = function () {
3             var oBox = document.getElementById('box');
4 
5             oBox.onclick = function () {
6                 alert(oBox.id);
7             }
8         };
9     </script>
复制代码

像上述的情况下就发生了内存泄漏,因为在闭包中创建了一个循环引用。可以通过以下方法得到解决:

复制代码
 1     <script>
 2         window.onload = function () {
 3             var oBox = document.getElementById('box');
 4 
 5             oBox.onclick = function () {
 6                 alert(oBox.id);
 7             };
 8 
 9             //方法一
10             window.onunload = function () {
11                 oBox.onclick = null;
12             }
13         };
14 
15         //方法二
16         window.onload = function () {
17             var oBox = document.getElementById('box');
18             var id = oBox.id;
19 
20             oBox.onclick = function () {
21                 alert(id);
22             };
23 
24             oBox = null;
25         };
26         
27     </script>
复制代码