What is a Closure :
Closure is a reference to a function together with the referencing environment.Two important things to note in the above definition is that closure comprises of two things as follow
- A reference to a function.
- Binding function's referencing environment (in our case local variables inside the function's scope).
function HelloWorld(){
var msg = "Hello World";
function PrintHelloWorld(){
alert(msg);
};
return PrintHelloWorld;
};
var referenceToPrintHelloWorld = HelloWorld();
referenceToPrintHelloWorld();
Output of this program : [Hello World]
In the above code snippet, function HelloWorld() returns a reference to PrintHelloWorld(). PrintHelloWorld() closes over the local variable "msg" of HelloWorld(), which is in its execution environment. Here execution environment is the scope in which this function in declared and that is scope of HelloWorld function. Hence this satisfies definition of closure.
Notice though "msg" is defined locally inside HelloWorld's scope but still when we call referenceToPrintHelloWorld() from scope outside of HelloWorld() it alerts the value "msg". This is the magic of closures which closes over any local variable in its scope.
A Use Case : Classic last value problem
Preparation code<html>
<body>
<button id="button1" >Button 1</button>
<button id="button2" >Button 2</button>
<button id="button3" >Button 3</button>
<button id="button4" >Button 4</button>
<button id="button5" >Button 5</button>
</body>
<script>
for (var i = 1; i <= 5; i++) {
document.getElementById('button' + i ).onclick = function() {
alert('You clicked on BUTTON with unique number : ' + i );
};
}
</script>
</html>
This is a simple code in which onclick event is attached to the buttons using a loop. When user clicks a button its unique number is supposed to be alerted, e.g When user clicks on the first button it is supposed to alerts "You clicked on BUTTON with unique number : 1". Where this unique number is supposed to be assigned during the loop execution.
Go ahead, run this program and see the output.
Output of this program irrespective of which button you press is always : [You clicked on BUTTON with unique number : 6].
No matter which button you click all the button have the same unique number "6" attached to them.
The root of this confusion is that all the onclick event refer to the same variable i , and at the end of the loop the value of i is 6. So whenever you click on any button it refers to the same variable i which has a value of 6 now. This is exactly the "last value" problem.
So how do you solve this problem ???
You might have guessed it by now and its closures ( though there are other way too). Since closures binds the context (in our case a unique number for every button).
So what we do to solve this problem we assign closures to onclick event rather that simple functions.
Here is the solution.
for (var i = 1; i <= 5; i++) {
document.getElementById('button' + i).onclick = (function(){
var uid = i;
return function(){
alert('You clicked BUTTON with unique number : ' + uid);
};
})();
};
In this solution the value of i is stored in the execution environment which is binded to the function that is returned by the self executing anonymous function.
This is not the best elegant solution. The variable uid is used in this example to just highlight that value of i is stored in the local variable uid which is in the execution environment.
Elegant way of doing this would be passing the value of i as argument to self executing functions scope.
for (var i = 1; i <= 5; i++) {
document.getElementById('button' + i).onclick = (function(uid){
return function(){
alert('You clicked BUTTON with unique number : ' + uid);
};
})(i);
};
P.S.
Closure is a fun thing in JavaScript and can be applied to problems where context of execution has to remembered. Go on and take a dive into closures.