前几天有人问关于javascript的闭包的问题,这里,首先引用一下《JavaScript权威指南》第6版中第八章第6节的内容,里面讲得非常详细:

   和其他大多数现代编程语言一样,JavaScript也采用词法作用域(lexical scoping),也就是说,函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。为了实现这种词法作用域,JavaScript函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包”(这个术语非常古老,是指函数变量可以被隐藏于作用域链之内,因此看起来是函数将变量“包裹”了起来)。

    从技术角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。定义大多数函数时的作用域链在调用函数时依然有效,但这并不影响闭包。当调用函数时闭包所指向的作用域链和定义函数时的作用域链不是同一个作用域链时,事情就变得非常微妙。当一个函数嵌套了另外一个函数,外部函数将嵌套的函数对象作为返回值返回的时候往往会发生这种事情。有很多强大的编程技术都利用到了这类嵌套的函数闭包,以至于这种编程模式在JavaScript中非常常见。当你第一次碰到闭包时可能会觉得非常让人费解,一旦你理解掌握了闭包之后,就能非常自如地使用它了,了解这一点至关重要。

    理解闭包首先要了解嵌套函数的词法作用域规则。看一下这段代码:

***********************************************************************************

var scope = "global scope";       //全局变量    
function checkscope(){        
    var scope = "local scope";    //局部变量        
    function f(){return scope;}   //在作用域中返回这个值        
    return f();    
}    
console.log(checkscope() );       //==>"local scope"


***********************************************************************************

checkscope()函数声明了一个局部变量,并定义了一个函数f(),函数f()返回了这个变量的值,最后将函数f()的执行结果返回。

    现在,我们把以上代码略作改变:

***********************************************************************************

 var scope = "global scope";            //全局变量
 function checkscope(){
     var scope = "local scope";         //局部变量        
     function f(){return scope;}        //在作用域中返回这个值      
     return f;    
}    
console.log(checkscope()()) ;           //==>"local scope"


***********************************************************************************

在这段代码中,我们将函数内的一对圆括号移动到checkscope()之后。checkscope()现在仅仅返回函数内嵌套的一个函数对象,而不是直接返回结果。在定义函数的作用域外面,调用这个嵌套的函数(包括最后一行代码的最后一对圆括号)会发生什么事情呢?

       回想一下词法作用域的基本规则:JavaScript函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的。嵌套在何时何地执行函数f(),这种绑定在执行f()时依然有效。因此最后一行代码返回“local scope”,而不是global scope。简而言之,闭包的这个特性强大到让人吃惊:它们可以捕捉到局部变量和参数),并一直保存下来,看起来像这些变量绑定到了在其中定义它们的外部函数。



 待续