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对象存储的是外部函数的引用(地址)

javascript闭包

问题又来了,如果我们想返回的是[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)的问题了。

你可能感兴趣的:(JavaScript)