The reason this is happening is that when you pass newData
to foo()
, you are passing a reference to that object. Then when you use setTimeout
with an anonymous function, that same object is "captured" inside that anonymous function (this is known as a "closure").
Your for
loop continues, and the object's value
property changes, so when the functions that you passed to setTimeout
are ultimately called, the object's value
property is now 2
, and that is what is displayed.
In your case, there is a simple solution. Just assign data.value
's current value to a variable inside your foo
function and use that when you call setTimeout
:
function foo(data) {
var val = data.value; // copy the value to a local variable
setTimeout(function(){
console.log(val);
},1000)
}
The reason the code works as expected when you use {value: i}
is that it results in you passing a whole new object to foo
every time, and that object is never modified after the fact. There are indeed some benefits to doing it this way, but there are also times when you only want to modify one property and not create a whole new copy. The above will allow you to do that.
The behavior of variables inside closures is an issue that comes up a lot in JavaScript development. See this for more discussion on the topic:
JavaScript closure inside loops – simple practical example