js也采用词法作用域(lexical scoping),也就是说,函数的执行依赖于变量作用域,js函数的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。
函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中成为『闭包』。
<script type="text/javascript">
//理解闭包首选要了解嵌套函数的词法作用域规则
var scope = "global scope"; //全局变量
function checkscope(){
var scope = "local scope"; //局部变量
function f(){ return scope;} //再作用域中返回这个值
return f();
}
checkscope(); //=>"local scope"
//现在我们对这段代码做一点改动,你知道返回什么?
var scope = "global scope"; //全局变量
function checkscope(){
var scope = "local scope"; //局部变量
function f(){ return scope;} //再作用域中返回这个值
return f;
}
checkscope()(); //返回值是什么?
</script>
在这段代码中,我们将函数内的一对圆括号移动到了checkscope()之后。
checkscope()现在仅仅返回函数内嵌套的一个函数对象,而不是直接返回结果。
再定义的函数作用域外,调用这个嵌套的函数会发送什么事情呢?
回想一下词法作用域链的基本规则:js函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的。
嵌套的函数f()定义在这个作用域链中,其中的变量scope一定是局部变量,不管在何时何地执行函数f(),这种绑定在f()时依然有效。因此最后一行代码返回"local scope",而不是"global scope"。
简言之,闭包的这个特性抢到到让人吃惊:它们可以捕捉到巨变变量(和参数),并一直保存下来,看起来像这些变量绑定到了其中定义它们的外部函数。