How do JavaScript closures work?
stackoverflow.com
stackoverflow.com
For example, take the function in the stackoverflow answer -
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
When you make a call to foo(10), pretend that the bound variables in the body of the function get assigned sequence numbers starting from 100 - function foo() {
v[100] = 10; // x = 10
v[101] = 3; // var tmp = 3;
return function (y) {
alert(v[100] + y + (++(v[101])));
}
}
So you get as the result, function (y) {
alert(v[100] + y + (++(v[101])));
}
'y' remains as such because it hasn't been bound to a value just yet. That will happen only when you call this result function.Now, when you call foo another time like foo(20), the sequence continues from 102 ...
function foo() {
v[102] = 20; // x = 20
v[103] = 3; // var tmp = 3;
return function (y) {
alert(v[102] + y + (++(v[103])));
}
}
So you get another function as the result - function (y) {
alert(v[102] + y + (++(v[103])));
}
The store now reads v[100] = 10, v[101] = 3, v[102] = 20 and v[103] = 3.It becomes clear what the two result functions do. Note that they do not share the same storage locations and therefore the two ++ calls increment different storage locations.
In this model, each "var" statement and each argument of a function causes the index assigned to be incremented on a function call, and unbound variables do not cause increments. The behaviour of closures created in javascript is as though such an indefinitely increasing numbering scheme is being used under the hood.
(edited a bit for clarity).
That's easy enough to test. var y=20;
function foo(x) {
var tmp = 3;
var y = 20;
return function (y) {
alert(x + y + (++tmp));
}
}var bar = foo(2); // bar is now a closure.
bar(10);
This makes no difference. The alert runs once, and displays 16.
https://github.com/raganwald/homoiconic/blob/master/2010/10/...
for (var i = 0; i < 5; i++) {
console.info(i);
}
This works fine. And the console displays 1, 2, 3 and 4. But let's suppose that you have the following code: for (var i = 0; i < 5; i++) {
$(DOMelement:eq(i)).click(function() {
console.info(i);
});
}
The console will always display "4" whichever DOMelement you clicked. Surprise? That's because it calls i which holds 4. JavaScript passed the argument by reference to i and by the time you clicked, the iterations already finished.JavaScript closures help solve this problem (Luckily). Here is how:
for (var i = 0; i < 5; i++) {
$(DOMelement:eq(i)).click(function() {
return function() {
console.info(i);
}
});
}
That's because JavaScript returns now a new function for each DOM element. Each new function holds the i value while iteration and now the final value.This should work okay:
for (var i = 0; i < 5; i++) {
$(DOMelement:eq(i)).click((function(i) {
return function() {
console.info(i);
}
}(i)));
}
Also surely DOMelement.eq(i) as opposed to DOMelement:eq(i)?Also, this feels like piling on, but I think the original (intentionally erroneous) example would print '5' repeatedly rather than '4'. var i ends up with the value 5.
for DOM part, I didn't understand your question. However, the right way to do it is
$(DOMelement:eq(i)).each();
to iterate through each element.function foo(o) { eval("var x = 10;"); with (o) { return function(e) { if (typeof e == "string") eval(e); return x; } } } this.x = 42; var f = foo({x : 37}); alert(f("var x = 13")); alert(f()); alert(f("delete x")); alert(f("delete x"));
Each call returns a different variable called "x".