个人理解

  1. var data = [];
  2. for (var i = 0; i < 3; i++) {
  3. data[i] = (function (i) {
  4. return function(){
  5. console.log(i);
  6. }
  7. })(i);
  8. }
  9. data[0]();//0
  10. data[1]();//1
  11. data[2]();//2

上面的循环相当与做了下面的事

  1. var data = [];
  2. data[0] = (function (i) {
  3. return function(){
  4. console.log(i);
  5. }
  6. })(0);
  7. //相当于
  8. data[0] = function(){
  9. console.log(0);
  10. }
  11. data[1] = (function (i) {
  12. return function(){
  13. console.log(i);
  14. }
  15. })(1);
  16. //相当于
  17. data[1] = function(){
  18. console.log(1);
  19. }
  20. data[2] = (function (i) {
  21. return function(){
  22. console.log(i);
  23. }
  24. })(2);
  25. //相当于
  26. data[2] = function(){
  27. console.log(2);
  28. }
  29. data[0]();//0
  30. data[1]();//1
  31. data[2]();//2

声明了三个自执行函数,这三个函数之间是没有联系的,每个都是独立的(相当于3个实例,参考下面的makeAdder函数和makeCounter函数)
data[0] 、 data[1] 、data[2] 都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 data[0] 的环境中,i 为 0。在 data[1] 的环境中,i 为 1。在 data[2] 的环境中,i 为 2。

网上案例

闭包是通过作用域链来将函数内部变量保存在内存中

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

这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。此处摘自阮一峰

  1. function makeAdder(x) {
  2. return function(y) {
  3. return x + y;
  4. };
  5. }
  6. var add5 = makeAdder(5);
  7. var add10 = makeAdder(10);
  8. console.log(add5(2)); // 7
  9. console.log(add10(2)); // 12

add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。

  1. var makeCounter = function(){
  2. var privateCounter = 0
  3. function changeBy(val){
  4. privateCounter += val
  5. }
  6. return {
  7. increment:function(){
  8. changeBy(1)
  9. },
  10. decrement:function(){
  11. changeBy(-1)
  12. },
  13. increment:function(){
  14. return privateCounter
  15. }
  16. }
  17. }
  18. var Conter1 = makeCounter();
  19. var Conter2 = makeCounter();
  20. console.log(Counter1.value()); /* logs 0 */
  21. Counter1.increment();
  22. Counter1.increment();
  23. console.log(Counter1.value()); /* logs 2 */
  24. Counter1.decrement();
  25. console.log(Counter1.value()); /* logs 1 */
  26. console.log(Counter2.value()); /* logs 0 */

请注意两个计数器 Counter1 和 Counter2 是如何维护它们各自的独立性的。每个闭包都是引用自己词法作用域内的变量 privateCounter 。

每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。

以这种方式使用闭包,提供了许多与面向对象编程相关的好处 —— 特别是数据隐藏和封装。