Possible Duplicate:
javascript for loop unexpected behaviour
I'am programming in node.js and i run into a small problem what is caused by some strange pass by reference problem.
i use the following code:
for(j in groups){
console.log(j, somefunction(groups[j]))
}
inside of the function some funky things are done with the data but afterwards i get the following as result:
3 data
3 data
3 data
3 data
3 data
3 data
instead of
1 data
2 data
3 data
4 data
5 data
6 data
but it keeps the correct amount of result..
Your quoted code doesn't do what you've listed, you probably lost something simplifying it for the question.
This code would have the effect you're describing, though:
for(j in groups){
doSomething(function() {
// Callback for `doSomething`
console.log(j, somefunction(groups[j]));
});
}
Note that now I'm creating a function (a callback for whatever doSomething
does), not just calling one.
The reason that happens is that the function being created has an enduring reference to the j
variable (and everything else in the execution context), not a copy of it as of when the function was created. It's called a closure over that execution context. So your loop runs, a series of calls to doSomething
start a series of things, and then later when the callbacks are called, j
is 3 and so it's the same for all of them.
The usual solution is to create functions that close over something that won't change before they get called, like this:
for(j in groups){
doSomething(makeCallback(j));
}
function makeCallback(jarg) {
return function() {
console.log(jarg, somefunction(groups[jarg]));
};
}
Now, we're using jarg
in our callback, rather than j
. Because jarg
is part of the context of the call to makeCallback
, it doesn't change between when we create the function and when it's called later.
Another way you can bind data to functions is to use Function#bind
(which effectively creates a closure in the background), which is an ES5 feature available in NodeJS because the V8 engine has it. Here's how that would look:
for(j in groups){
doSomething(function(jarg) {
// Callback for `doSomething`
console.log(jarg, somefunction(groups[jarg]));
}.bind(this, j)); // <== Note the bind
}
or less confusingly (and quite possibly more efficiently):
for(j in groups){
doSomething(handler.bind(this, j));
}
function handler(jarg) {
// Callback for `doSomething`
console.log(jarg, somefunction(groups[jarg]));
}
More about closures:
ive found if i use var j = 0
for(i in groups){
j = i
the system does work how but it's not the best awnser
Do it this way :-
for(var j in groups) { //Your code }
j is not returning the correct value because you have assigned j at a global scope. Hope this help!