前面几篇文章中提到过,作用域链以及闭包的概念,这里就不一一重复了,
作用域链的这种配置机制引出了一个值得注意副作用,既闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。
function createFunctions(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return i;
}
}
return result;
}
从上面的代码,这个函数会返回一个函数数组。表面上看,似乎每个函数都应该返回自己的索引值,既位置0的函数返回0,依次类推。但实例每个函数都会返回10.
因为每个函数的作用域链中都保存着 createFunctions() 函数的活动对象,所以它们引用的都是同一个变量i.
那怎么解决这个问题尼? 可以通过创建另一个匿名函数强制让闭包的行为符合预期,如下所示
function createFunctions(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(num){
return function(){
return num;
}
}(i);
}
return result;
}
代码修改为上面的时候,似乎符合我们的初衷了,
var result = createFunctions();
alert(result[0]()); //0
alert(result[1]()); //1
使用一个外部匿名函数,并且自己内部定义了num 变量,在执行外部匿名函数时传递的i
参数赋值给了num变量(值传递 也可以说是cope一个值),这样返回回去的函数访问就外部匿名函数中保存的 num 变量保存的变量值。
上面须要注意的是:
红色部分,循环一次就相当于声明一个函数(相当于 变量对象 个数就是循环次数),
而不像 createFunctions 在整个循环执行完成的时候都是同一个变量对象(活动对象);所以在外部执行result保存的函数时,返回值都10的原因;
记得前面提到过,当每个函数执行时,都会有一个对应的变量对象作(活动对象)其内部的 num 保存的是 i的副本值 ;所以蓝色部分匿名函数的作用域链中包含的外部匿名外部函数活动对象都是不一样,
这也就是其返回的结果和我们预期一样的原因。