This describes the common mistake with using closures in JavaScript.
A function defines a new environment
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 0
For 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.
Closures in loops
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 1
Notice 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.
For a detailed discussion, please see JavaScript closure pitfalls and usage
This describes the common mistake with using closures in JavaScript.
A function defines a new environment
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 0
For 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.
Closures in loops
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 1
Notice 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.
For a detailed discussion, please see JavaScript closure pitfalls and usage
This describes the common mistake with using closures in JavaScript.
A function defines a new environment
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 0
For 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.
Closures in loops
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 1
Notice 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.
This describes the common mistake with using closures in JavaScript.
A function defines a new environment
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 0
For 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.
Closures in loops
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 1
Notice 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.
For a detailed discussion, please see JavaScript closure pitfalls and usage