我对javascript的特定行为有疑问:
我有一个对象,我想填充生成的函数。每个函数都包含一个在函数生成循环期间更改的变量。
我的问题是,在将函数分配给对象时,不会替换变量。相反,对变量的引用保留在函数中,并且在执行函数时,只记住变量的最后一个值。
这是一个最小的例子(也在jsfiddle上:http://jsfiddle.net/2FN6K/):
var obj = {};
for (var i = 0; i < 10; i++){
var nr = i;
obj[i] = function(){
console.log("result: " + nr);
}
}
for (var x = 0; x < 10; x++){
obj[x]();
}
第二个循环执行所有生成的函数,并且所有函数都打印9作为结果。但我希望他们打印变量在生成时的值(0,1,2,...)。
有办法做到这一点吗?提前谢谢。
答案 0 :(得分:1)
问题是您创建的所有函数都在共享对同一nr
变量的引用。当你调用它们时,它们使用该引用获取值,因此所有这些都得到相同的结果。
像这样解决:
for (var i = 0; i < 10; i++){
(function(nr) {
obj[nr] = function(){
console.log("result: " + nr);
}
})(i);
}
答案 1 :(得分:1)
一种方法是调用返回函数的函数:
function makeFunc(i) {
return function() {
console.log("result: " + i);
}
}
for (...) {
obj[i] = makeFunc(i);
}
另一种方法是立即调用函数表达式:
for (i = 0; ...; ...) {
(function(i) {
obj[i] = function() {
console.log("result: " + i);
}
})(i);
}
在后一种情况下,(function(i) ... )(i)
导致i
的永久绑定作为参数传递给内部函数范围内的外部函数
答案 2 :(得分:1)
你的猜测是正确的,是的,有一个解决方案:
obj[i] = function( nr_copy ) {
return function() {
console.log("result: " + nr_copy);
};
}( nr );
JavaScript变量的作用域是函数级别,与其他一些块结构语言不同。也就是说,在for
循环中声明“nr”的事实并不会使它成为该块的“本地” - 效果与在函数顶部声明它的效果完全相同
通过使用该匿名函数引入另一个函数作用域,您可以创建“nr”值的新副本,然后可以将该函数私有地访问返回的实际函数。当“obj”数组的那个插槽被初始化时,这些函数中的每一个都将拥有它自己的“nr”值的副本。
答案 3 :(得分:0)
你想要的是为你创建的每个函数创建一个闭包 但是,var(s)没有块范围,因此您的代码与:
相同var obj = {};
var i;
var nr;
for (i = 0; i < 10; i++){
nr = i;
obj[i] = function(){
console.log("result: " + nr);
}
}
希望所有函数更明显地引用完全相同的'nr'var。
你想要做的事情意味着每次创建一个新的范围,这可能是使用bind完成的,但是让我们坚持你的原始意图并每次使用lambda构建一个新的闭包:
var obj = {};
for (var i = 0; i < 10; i++) {
obj[i] = (function(){
var this_nr = i;
return function(){
console.log("result: " + this_nr);
}
}() );
}