Javascript闭包(1)

变量做用域

简而言之,JS变量存在于两个做用域里,即全局做用域和函数内的局部做用域。全局做用域的变量是经过在容器(如浏览器的window)里的定义的,局部做用域是定义在函数内部。浏览器

做用域链

首先,函数可使用全局做用域的变量。其次,函数内部能够定义嵌套的子函数,而嵌套的函数能够递归般的使用上一级函数做用域内的变量直至全局变量,这就构成了一个做用域链。闭包

做用域链的打破

每一个函数的绑定都生成并维持了一个闭包,一般状况下,一个函数被调用以后,这个闭包环境就会被回收。可是若是函数在调用的时候,返回了一些内部的函数,那么等因而创建了一个通道,将内部做用域暴露给外部,从而打破了做用域链。造成了一条区别于自内而外到做用域链的新链接。函数

var F = function(){
        var b = 2;
        return function(){
            b += 1;
            return b;
        };
    }
    var inner = F();

    window.console.log(inner());//3
    window.console.log(inner());//4
    
    var another = F();
    window.console.log(another()); //3
    window.console.log(inner());//5

上述代码,能够看出一下两点:code

  1. F()返回的是一个函数,这个函数调用的结果是返回b的值。这个做用域链inner->function->b,所以inner=F()后,就产生了一个新的做用域,维持着b这个局部变量不被回收。两次调用,不一样的返回值,说明b还在做用域内,没有被回收。
  2. 做用域链是相互独立的,inner和another维护着两个独立的变量做用域链。

闭包的本质

来看一个经典的例子:递归

function F(){
    var arr = [],i;
    for(i = 0; i < 3; i++){
            arr[i] = function(){
                    return i;
           }
        }
    return arr;
}
window.console.log(arr[0]());    //3
window.console.log(arr[1]());    //3
window.console.log(arr[2]());    //3

上述代码,arr里包含了三个函数,都是 return i。 可是这个i的值,为何是3,而不是0,1,2呢?这进一步说明,闭包维护的是变量之间的引用关系,而不是这些变量在定义的时候的值。那么如何使arr如预期那样工做呢?其实目标就是让arr存的三个函数有独立的做用域链。如上一节分析的那样,每次函数的调用,会创建一个做用域链,所以只要使arr里的三个变量是三次函数调用,就能够创建三个独立的做用域链。那么如何使arr的元素从函数变成函数调用呢?尝试如下两个方法: 1.当即调用函数作用域

function FF(){
        var arr = [];
        for(var i = 0; i < 3; i++){
            arr[i] = (function(x){
                return function(){
                    return x;
                }
            })(i);
        }
        return arr;
    }
    var arr = FF();

    window.console.log(arr[0]());//0
    window.console.log(arr[1]());//1
    window.console.log(arr[2]());//2
  1. 内部函数
function FF(){
        var arr = [];
        function proxy(x){
            return function(){
                return x;
            }
        }
        for(var i = 0; i < 3; i++){
            arr[i] = proxy(i);
        }
        return arr;
    }
    var arr = FF();

    window.console.log(arr[0]());
    window.console.log(arr[1]());
    window.console.log(arr[2]());

其实两个方法本质上是一个方法。io

相关文章
相关标签/搜索