JavaScript 闭包
作用域链:只有内层函数可以调用外层变量,形成一条单向的作用域链
词法作用域:不同的函数之间不共享词法作用域,可以通过闭包来实现共享
作用域链与词法作用域样例
1 // 作用域链
2 var a = 1;
3
4 function test() {
5 var b = 2;
6
7 function test1() {
8 // 在test1()中可以调用外层的变量a和b
9 // 但是在外层无法调用内层的变量,形成了一条作用域链
10 var c = 3;
11 console.log(a);
12 console.log(b);
13 return b;
14 }
15 test1();
16 }
17 test();
18
19 // 词法作用域
20 // 不同的函数之间不共享词法作用域,可以通过闭包来实现共享
21 // 在这种写法中,错误信息提示d未定义
22 // function f1() {
23 // var d = 333;
24 // return f2();
25 // }
26
27 // function f2() {
28 // return d;
29 // }
30 // console.log(f1());
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
闭包:
- 在正常情况下,只有function2可以访问function1中的变量var a 和var b
- 如果想要在全局作用域中访问内层变量,就需要用到"闭包"
- 即借function2来调用function1中的变量

优点:
- 可以突破全局作用域链,调用函数内部变量
- 退出后函数不会被销毁,而是保留在内存中
- 作为迭代器来使用
缺点:
- 闭包会使函数中的变量都保存在内存中,内存消耗很大,不能滥用闭包。在IE中可能导致内存泄漏。在退出函数之前,尽量将不使用的局部变量全部删除
- 闭包会在父函数外部,改变父函数内部变量的值。所以如果把父函数作为对象Object使用,把闭包当作公用方法Public Method,把内部变量作为它的私有属性Private Value,此时注意不要随便改变父函数内部变量的值
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
实现形式:
- Demo1:通过返回函数的函数形式来返回f1中的变量

- Demo2:利用全局变量进入到函数内部来调用

闭包的基础形式
1 // 通过闭包突破全局作用域链
2
3 // Demo1:使用返回函数的函数来实现闭包
4 function f1() {
5 var a = 'aaa';
6 return function() {
7 return a;
8 }
9 }
10 var a1 = f1();
11 // f1()返回的是function(){return a;}
12 console.log(typeof a1);
13 // 要打印a的值则要用a1()
14 console.log(a1());
15 // 或使用二次调用
16 var a2 = f1()();
17 console.log(a2);
18
19 // Demo2:利用全局变量进入到函数内部来调用
20 var temp;
21 function f3(){
22 var b = 'bbb';
23 temp = function(){
24 return b;
25 }
26 }
27 // 先调用f3(),将function()赋给全局变量temp
28 f3();
29 // 执行temp()得到变量b的内容
30 console.log(temp());
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
闭包的应用:基本形式/迭代器
1 // 闭包的应用
2 // Demo1:基本应用
3 function f1() {
4 var n = 1;
5 // test是全局变量
6 test = function() {
7 n++;
8 }
9
10 function f2() {
11 console.log(n);
12 return 'f2 return';
13 }
14 // 调用f1时返回f2()的指针
15 return f2;
16 }
17 // res调用f1()时,返回f2给res
18 var res = f1();
19 // 打印res可以看到f2()的内容
20 console.log(res);
21 // 执行f2的内容可以得到n与f2()的返回值
22 console.log(res());
23 // 执行test()函数后n++
24 test();
25 // 此时调用n的值即为2
26 console.log(res());
27 // 说明变量n始终保存在内存中,并不会因为f1()执行结束而销毁
28 // f1是f2()的复函数,f2又被赋予给全局变量res,f2又依赖f1,所以f1未被销毁
29
30 // *******************************************************************
31 // Demo2:设置变量访问控制,在外部不会被访问到
32 // 全局作用域中变量getValue和setValue用于调用
33 var setValue, getValue;
34 // 设置自调用函数,建立初始值
35 (function() {
36 var num = 0;
37 getValue = function() {
38 return num;
39 };
40 setValue = function(x) {
41 num = x;
42 };
43 })();
44 // 默认得到初始值0
45 var getNum = getValue();
46 console.log(getNum);
47 // 给num赋值
48 setValue(10);
49 // 获取获取到的值
50 var getNum = getValue();
51 console.log(getNum);
52
53 // *******************************************************************
54 // Demo3:迭代器效果
55 // 对数组操作,每次调用则返回下一个元素
56 var arr1 = ['a', 'b', 'c', 'd', 'e'];
57
58 function iterator(arr) {
59 var i = 0;
60 return function() {
61 return arr[i++];
62 };
63 }
64 var next = iterator(arr1);
65 console.log(next());
66 console.log(next());
67 console.log(next());
68 console.log(next());
69 console.log(next());
70
71 // *******************************************************************
72 // 迭代器的第二种形式
73 function iterator2() {
74 var arr2 = [];
75 var i;
76 // 每次循环时自调用function(x),返回function(){return x};
77 for (i = 0; i < 3; i++) {
78 arr2[i] = (function(x) {
79 return function() {
80 return x;
81 };
82 })(i);
83 }
84 return arr2;
85 }
86 // 在这里next2是一个数组,数组的内容是function(){return x;};
87 var next2 = iterator2();
88 console.log(next2);
89 // next2[0]执行return x;
90 console.log(next2[0]());
91 console.log(next2[1]());
92 console.log(next2[2]());
93
94 // *******************************************************************
95 // 迭代器的第三种形式
96 function iterator3() {
97 // 闭包函数
98 function test3(x) {
99 return function() {
100 return x * 10;
101 }
102 }
103 var arr3 = [];
104 var i;
105 for (i = 0; i < 3; i++) {
106 // 每次循环时调用闭包函数赋给a[i];
107 arr3[i] = test3(i);
108 }
109 return arr3;
110 }
111 var next3 = iterator3();
112 console.log(next3);
113 console.log(next3[0]());
114 console.log(next3[1]());
115 console.log(next3[2]());


浙公网安备 33010602011771号