闭包的概念

在JavaScript高级程序设计(第3版)中对闭包的定义是:闭包是指有有权访问另一个函数作用域中的变量的函数。

闭包的作用

(1) 让变量长期驻扎在内存当中

  1. function fn1(){
  2. var a = 5;
  3. function fn2(){
  4. console.log(a);
  5. }
  6. return fn2;
  7. }
  8. fn = fn1(); //fn1执行完后,变量a并没有被垃圾回收机制收回
  9. fn(); //在这里,还可以访问到fn1中的变量a

(2) 避免全局变量的污染

  1. var a=1;
  2. // 普通函数
  3. function fn1(){
  4. a++;
  5. console.log(a)
  6. }
  7. fn1(); //2
  8. fn1(); //3
  9. console.log(a); //3 全局变量被改变
  10. // 使用闭包之后的函数:通过闭包实现每次调用a累加,同时又不会改变全局变量
  11. function fn2(){
  12. var a=1;
  13. return function fn3(){
  14. a++;
  15. alert(a);
  16. }
  17. }
  18. fn=fn2();
  19. fn(); //2
  20. fn(); //3
  21. console.log(a); //1 全局变量不变

(3)让函数拥有私有成员

  1. // 让函数拥有私有成员
  2. var fn1 = (function (){
  3. var a=1;
  4. // 特权函数
  5. function fn2(){
  6. a++;
  7. console.log(a)
  8. }
  9. // 特权函数
  10. function fn3(){
  11. a++;
  12. console.log(a);
  13. }
  14. return {
  15. "fn2":fn2,
  16. "fn3":fn3
  17. }
  18. })();
  19. fn1.fn2(); //2
  20. fn1.fn3(); //2
  21. console.log(a);//undefined
  22. fn2();//undefined
  23. fn3();//undefined

闭包的注意事项

闭包在IE8-下会引发内存泄漏:内存泄漏就是指浏览器不关闭,内存一直不会被释放

在理解内存泄漏时,我们先来了解一下JS中的垃圾回收机制:

JS中的内存回收是自动回收的,主要有两种方式:

  1. (1) 标记清除
  2. 变进入环境(例如,在函数中声明一个变量),则将这个变量标记为'进入环境',当变量离开环境时,则将其标记为离开环境。垃圾收集器会自动回收那些离开环境的变量所占用的内存

(2) 引用计数

  1. 引用计数的含义是跟踪每一个值被引用的次数。当声明一个变量并将一个值赋给该变量,则这个值的引用次数加1。如果这个变量又取了另外一个值,则这个值得引用次数减1,当这个值得引用次数变为0时,就可以将其占用的内存空间回收回来。
  2. 内存泄漏就是由于引用计数方式中的循环引用造成的,在下面的例子中,oBjectAobjectB分别指向一个Object类型的对象,则这两个对象的引用计数都是1,然后oBjectAobjectB通过各自的属性互相引用,oBjectAobjectB指向的那两个对象的引用计数都变成了2,这样就造成内存无法回收。(这里希望大家搞 清楚一个概念,oBjectAobjectB的值才是对象,oBjectAobjectB本身是变量)。现代浏览器都是采用标记清除的垃圾回收策略,但是在`IE8-`中的BOMDOM并不是原生的JavaScript对象,其BOMDOM使用c++以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数策略
  1. function fn(){
  2. var objectA = new Object();
  3. var objectB = new Object();
  4. objectA.attr1 = objectB;
  5. objectB.attr = objectA;
  6. }