This question already has an answer here:
I have read a number of explanations about closures and closures inside loops. I have a hard time understanding the concept. I have this code: Is there a way to reduce the code as much as possible so the concept of closure can be made clearer. I am having a hard time understanding the part in which the i
is inside two parenthesis. Thanks
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function (num) {
return function () {
alert(num);
};
}(i);
document.body.appendChild(link);
}
}
window.onload = addLinks;
I've been programming in JavaScript for a long time, and "closure in a loop" is a very broad topic. I assume you are talking about the practice of using
(function(param) { return function(){ ... }; })(param);
inside of a for loop in order to preserve the "current value" of the loop when that inner function later executes...The code:
Output:
As you can see by the output, all of the inner callback functions all point to the same
i
, however, since each had its own 'closure', the value ofx
is actually stored as whateveri
was at the time of the outer function's execution.Commonly when you see this pattern, you would use the same variable name as the parameter and the argument to the outer function:
(function(i){ })(i)
for instance. Any code inside that function (even if executed later, like a callback function) is going to refer toi
at the time you called the "outer function".WARNING: Long(ish) Answer
This is copied directly from an article I wrote in an internal company wiki:
Question: How to properly use closures in loops? Quick answer: Use a function factory.
or the more easily readable version:
This often confuse people who are new to javascript or functional programming. It is a result of misunderstanding what closures are.
A closure does not merely pass the value of a variable or even a reference to the variable. A closure captures the variable itself! The following bit of code illustrates this:
Clicking the element 'foo' will generate an alert box with the message: "Goodbye!". Because of this, using a simple closure in a loop will end up with all closures sharing the same variable and that variable will contain the last value assigned to it in the loop. For example:
All elements when clicked will generate an alert box with the number 10. In fact, if we now do
i="hello";
all elements will now generate a "hello" alert! The variable i is shared across ten functions PLUS the current function/scope/context. Think of it as a sort of private global variable that only the functions involved can see.What we want is an instance of that variable or at least a simple reference to the variable instead of the variable itself. Fortunately javascript already has a mechanism for passing a reference (for objects) or value (for strings and numbers): function arguments!
When a function is called in javascript the arguments to that function is passed by reference if it is an object or by value if it is a string or number. This is enough to break variable sharing in closures.
So:
A closure is a construct in which you reference a variable outside the scope in which it's defined. You usually talk about closures in the context of a function.
Here, I define the variable message, and define a function that references message. When I define the function to use message, I am creating a closure. This means helloFunction holds a reference to message, so that I can continue to use message, even outside of the scope (the loop body) where message is defined.
Addendum
The (i) in parenthesis is a function call. What's happening is:
link.onclick = function() { alert(i); };
To answer the last part of your questions. The two parenthesis invoke the function as any other functions. Why you do it here is that you want to keep what the variable "i" is just at that time. So what it does is, invoke the function, the i is sent as a argument "num". Since it's invoke it will remember the value nume in variable links own scoop.
If you did't to this all link click would result in an alert saying "5"
John Resig, founder of jQuery, has a really nice online presentation explaining this. http://ejohn.org/apps/learn/
..fredrik
Well, the "problem" with closures in such a case is, that any access to
i
would reference the same variable. That is because ofECMA-/Javascripts
function scope
orlexical scope
.So to avoid that every call to
alert(i);
would display a5
(because after the loop finished i === 5), you need to create a new function which invokes itself at runtime.To achieve this, you need to create a new function, plus you need the extra paranthesis at the end, to
invoke the outer function
immediately, solink.onclick
has now the returned function as reference.