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: