javascript闭包

在javascript中变量有全局作用域和局部作用域。通常,函数内部可以访问全局变量,也可以访问用var声明的局部变量,但是在函数外部不能访问函数内部的局部变量。那么,有时候我们要访问局部变量,如何访问函数内部的局部变量呢?可以用闭包。通俗的讲,闭包就是函数的返回值是一个函数(不是变量),这个返回的函数引用了外部函数的变量。

 1     function add() {
 2 
 3         arg = arguments;
 4 
 5         var add_number = function() {
 6 
 7             var sum = 0;
 8 
 9             for (var i = 0; i < arg.length; i++) {
10 
11                 sum += arg[i];
12 
13             }
14 
15             return sum;
16 
17         }
18 
19         return add_number;
20 
21     }
22 
23   var temp =  add(1, 2, 10)();
24 
25     console.info(temp);    //13
26 
27     
28 
29 console.info(arg);    //[1, 2, 10]

 

咦?在函数外面竟然还能访问函数内部的变量arg?这就是闭包的神奇特效。因为add()的返回值是一个函数,再把这个函数赋值给一个全局变量,返回值存储有指向其父函数的地址,所以现在全局变量temp就有指向add函数的变量arg的指针,这个指针被存储在内存中(函数执行结束后没有释放),自然就能够在全局范围内访问局部变量咯。

特别注意:调用函数,返回的函数中如果引用了外部函数的变量,那么就是地址引用,而不是值的引用,如果引用地址指向的变量变化,那么变量跟着变化。见以下:

 1 function closureArray(){
 2 
 3     var func = new Array();
 4 
 5     for(var i = 0;i < 10;i++){
 6 
 7         func[i] = function(){
 8 
 9             return i;
10 
11         }
12 
13     }
14 
15     return func;
16 
17 }
18 
19  
20 
21 (closureArray())[5](); //10

 

 

为什么得到的结果是10而不是0...9呢,因为闭包内的匿名函数中的arguments对象存储的是外部函数的引用(地址)

问题又来了,如果我们想返回的是[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]呢,很简单,只需要破坏闭包函数对外部函数的引用就可以了:

 1 function closureArray(){
 2     var func = new Array();
 3     for(var i = 0;i < 10;i++){
 4         func[i] = (function(temp){
 5             return temp;
 6         })(i);    //把对外部的引用复制给一个块级作用域的变量,每次块级作用域执行完成之后,就会释放引用,下一次调用又会重新复制,从而改变地址
 7     }
 8     return func;
 9 }
10 
11 var arr = closureArray();
12 console.info(arr);    //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 

说到这里,又有疑问了,为什么闭包内部引用外部变量存储的是外部函数的引用(而不是值)呢?

这个就是函数作用域链(scope)的问题了。

posted @ 2014-06-05 16:12  一叶(foolishnoob)  阅读(232)  评论(1编辑  收藏  举报