《Javascript高级程序设计》上对闭包的定义是:有权限访问另一个函数作用域中的变量的函数。也就是说,闭包是一个函数,那什么样的函数才能是闭包呢?他能访问另一个函数作用域中的变量。这样的解释让我们直接想起了一个函数的内部函数,因为根据作用域链的规则,只有嵌套的函数才能达到这个效果。并且这个闭包函数是作为父函数的返回值返回,而且这个闭包函数通常是个匿名函数。
可能说这么多的书面语依旧很晦涩难懂,所以嘞,就举个例子来帮助理解。
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return i;
};
}
return result;
}
首先 i 是 createFunction 的活动对象,但被一个匿名函数使用并作为返回值而形成闭包。因为匿名函数需要将i 返回,所以i同样被添加为匿名函数的活动对象,也就是 i<10 中的 i,和 return i 中的i 是同一个 i 而并非一般情况下的值传递。而 createFunction 返回时, i的值必然已经成为10了,前面已经说了i 是同一个i 那匿名函数内部的 i也是10 了。
再看一段常用解决方案的代码:
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
上面这段代码添加了另一个有参的匿名函数。与上面代码相同的是无参的匿名函数因为返回了父函数的变量,所以把父函数的num活动对象添加为自己的活动对象,但有参匿名函数的num是由createFunction逐次引用而来的(因为值传递的缘故,createFunction返回之前的所有i++都被记录在了num里)。所以num值为从0到9 逐次i++而来的。
用这两个例子可以清楚的理解什么是闭包,用什么样的方式来解决闭包带给我的不想要的效果。再次总结一下,想要形成闭包,需要有一个函数访问了另一个函数作用域里的变量并添加为自己的活动对象。这样就导致变量不再是值传递而是就是同一个变量了。解决方式就是在添加一个可以值传递的匿名函数来取得值传递的结果。