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>