What is a practical use for a closure in JavaScript?
I'm trying my hardest to wrap my head around JavaScript closures.
I get that by returning an inner function, it will have access to any variable defined in its immediate parent.
Where would this be useful to me? Perhaps I haven't quite got my head around it yet. Most of the examples I have seen online don't provide any real world code, just vague examples.
Can someone show me a real world use of a closure?
Is this one, for example?
var warnUser = function (msg) {
var calledCount = 0;
return function() {
calledCount++;
alert(msg + 'nYou have been warned ' + calledCount + ' times.');
};
};
var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();
I've used closures to do things like:
a = (function () {
var privatefunction = function () {
alert('hello');
}
return {
publicfunction : function () {
privatefunction();
}
}
})();
As you can see there, a
is now an object, with a method publicfunction
( a.publicfunction()
) which calls privatefunction
, which only exists inside the closure. You can NOT call privatefunction
directly (ie a.privatefunction()
), just publicfunction()
.
Its a minimal example but maybe you can see uses to it? We used this to enforce public/private methods.
Suppose, you want to count the number of times user clicked a button on a webpage.
For this, you are triggering a function on onclick
event of button to update the count of the variable
<button onclick="updateClickCount()">click me</button>
Now there could be many approaches like:
1) You could use a global variable , and a function to increase the counter :
var counter = 0;
function updateClickCount() {
++counter;
// do something with counter
}
But, the pitfall is that any script on the page can change the counter, without calling updateClickCount()
.
2) Now, You might be thinking of declaring the variable inside the function:
function updateClickCount() {
var counter = 0;
++counter;
// do something with counter
}
But, Hey! Every time updateClickCount()
function is called, the counter is set to 1 again.
3) Thinking about Nested functions ?
Nested functions have access to the scope "above" them.
In this example, the inner function updateClickCount()
has access to the counter variable in the parent function countWrapper()
function countWrapper() {
var counter = 0;
function updateClickCount() {
++counter;
// do something with counter
}
updateClickCount();
return counter;
}
This could have solved the counter dilemma, if you could reach the updateClickCount()
function from the outside and you also need to find a way to execute counter = 0
only once not everytime.
4) Closure to the rescue! (self-invoking function) :
var updateClickCount=(function(){
var counter=0;
return function(){
++counter;
// do something with counter
}
})();
The self-invoking function only runs once. It sets the counter
to zero (0), and returns a function expression.
This way updateClickCount
becomes a function. The "wonderful" part is that it can access the counter in the parent scope.
This is called a JavaScript closure . It makes it possible for a function to have "private" variables.
The counter
is protected by the scope of the anonymous function, and can only be changed using the add function!
More lively example on Closure:
<script>
var updateClickCount=(function(){
var counter=0;
return function(){
++counter;
document.getElementById("spnCount").innerHTML=counter;
}
})();
</script>
<html>
<button onclick="updateClickCount()">click me</button>
<div> you've clicked
<span id="spnCount"> 0 </span> times!
</div>
</html>
The example you give is an excellent one. Closures are an abstraction mechanism that allow you to separate concerns very cleanly. Your example is a case of separating instrumentation (counting calls) from semantics (an error-reporting API). Other uses include:
Passing parameterised behaviour into an algorithm (classic higher-order programming):
function proximity_sort(arr, midpoint) {
arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; });
}
Simulating object oriented programming:
function counter() {
var a = 0;
return {
inc: function() { ++a; },
dec: function() { --a; },
get: function() { return a; },
reset: function() { a = 0; }
}
}
Implementing exotic flow control, such as jQuery's Event handling and AJAX APIs.