我有一个这样的程序:
var newData={};
for(var i=0;i<3;i++){
newData.value=i;
foo(newData);
}
function foo(data){
setTimeout(function(){
console.log(data.value)
},1000)
}
我以为我会看到结果0 1 2
,但却给了我2 2 2
。
然后,我将第3行中的newData.value=i
更改为newData={value:i}
,结果显示为0 1 2
,正如我所希望的那样。
我很困惑。这两种方法有什么区别?
答案 0 :(得分:1)
发生这种情况的原因是,当您将newData
传递给foo()
时,您将引用传递给该对象。然后当你使用setTimeout
匿名函数时,同一个对象被“捕获”在匿名函数中(这被称为“闭包”)。
您的for
循环继续,对象的value
属性发生更改,因此当您最终调用传递给setTimeout
的函数时,对象的value
属性现在是2
,这就是显示的内容。
在您的情况下,有一个简单的解决方案。只需将data.value
的当前值分配给foo
函数中的变量,并在调用setTimeout
时使用该变量:
function foo(data) {
var val = data.value; // copy the value to a local variable
setTimeout(function(){
console.log(val);
},1000)
}
使用{value: i}
时代码按预期工作的原因是,每次都会将一个全新对象传递给foo
,并且该对象在事后不会被修改。这样做确实有一些好处,但有时你只想修改一个属性而不是创建一个全新的副本。以上将允许你这样做。
闭包内变量的行为是一个在JavaScript开发中出现的问题。有关该主题的更多讨论,请参阅此内容: JavaScript closure inside loops – simple practical example