This describes the common mistake with using closures in JavaScript.
Consider:
function makeCounter()
{
var obj = {counter: 0};
return {
inc: function(){obj.counter ++;},
get: function(){return obj.counter;}
};
}
counter1 = makeCounter();
counter2 = makeCounter();
counter1.inc();
alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0For each time makeCounter is invoked, {counter: 0} results in a new object being created. Also, a new copy of obj
is created as well to reference the new object. Thus, counter1 and counter2 are independent of each other.
Using a closure in a loop is tricky.
Consider:
var counters = [];
function makeCounters(num)
{
for (var i = 0; i < num; i++)
{
var obj = {counter: 0};
counters[i] = {
inc: function(){obj.counter++;},
get: function(){return obj.counter;}
};
}
}
makeCounters(2);
counters[0].inc();
alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1Notice that counters[0] and counters[1] are not independent. In fact, they operate on the same obj!
This is because there is only one copy of obj shared across all iterations of the loop, perhaps for performance reasons.
Even though {counter: 0} creates a new object in each iteration, the same copy of obj will just get updated with a
reference to the newest object.
Solution is to use another helper function:
function makeHelper(obj)
{
return {
inc: function(){obj.counter++;},
get: function(){return obj.counter;}
};
}
function makeCounters(num)
{
for (var i = 0; i < num; i++)
{
var obj = {counter: 0};
counters[i] = makeHelper(obj);
}
}This works because local variables in the function scope directly, as well as function argument variables, are allocated new copies upon entry.