Explanation of Closure with examples
<html>
<head>
<script type="text/javascript" src="js/lib/jquery-1.10.2.min.js"></script>
<script>
$( document ).ready(function() {
$('#js-btn-getfoo').on('click', function() {
alert('Current value of Foo is: ' + getsetVals.getFoo());
});
$('#js-btn-getbar').on('click', function() {
alert('Current value of Bar is: ' + getsetVals.getBar());
});
$('#js-btn-setbar').on('click', function() {
getsetVals.setBar(1);
});
$('#js-btn-setfoo').on('click', function() {
getsetVals.setFoo(1);
});
});
var setCompleted = (function () {
var foo = 0;
var bar = 0;
// some code related to moduleA
// ...
function updateLog() {
$('#events-log').append('<tr><td>' + foo + '</td><td>' + bar + '</td></tr>');
}
return {
onBarUpdated: function (newValue) {
bar = newValue;
updateLog();
},
onFooUpdated: function (newValue) {
foo = newValue;
updateLog();
}
};
}());
var getsetVals = (function () {
var foo = 0;
var bar = 0;
return {
getFoo: function() {
return foo;
},
setFoo: function (adder) {
foo = foo + adder;
setCompleted.onFooUpdated(foo);
},
getBar: function() {
return bar;
},
setBar: function (adder) {
bar = bar + adder;
setCompleted.onBarUpdated(bar);
}
};
}());
</script>
<style>
table {
width: 200px;
}
table td {
text-align: center;
}
</style>
</head>
<body>
<input type="button" id="js-btn-setfoo" value="+1 Foo">
<input type="button" id="js-btn-setbar" value="+1 Bar">
<input type="button" id="js-btn-getfoo" value="Get Foo">
<input type="button" id="js-btn-getbar" value="Get Bar">
<table id="events-log">
<tr>
<td>FOO</td>
<td>BAR</td>
</tr>
</table>
</body>
</html>/*
------------------------------------------------------------------------------------
------------------------- WHAT IS A CLOSURE IN JAVASCRIPT ? ------------------------
------------------------------------------------------------------------------------
*/
/*
Closures mean that you can save some data inside a function that's only
accessible to a specific returning function, i.e the returning function keeps
its execution environment.
Closure is whenever you see the function keyword within another function,
the inner function has access to variables in the outer function.
A function doesn't have to return in order to be called a closure.
Simply accessing variables outside of your immediate lexical scope creates a closure.
*/
/*
------------------------------------------------------------------------------------
------------------------- WHAT CAN BE DONE WITH CLOSURES ? -------------------------
------------------------------------------------------------------------------------
*/
/* a better alternative to using global variables and for functions like setTimeout()
/*
------------------------------------------------------------------------------------
---- PROVIDE PARAMETERS FOR THE EXECUTION OF A FUNCTION PRIOR TO ITS EXECUTION -----
------------------------------------------------------------------------------------
*/
/* http://jibbering.com/faq/notes/closures/ */
/*
A common use for a closure is to provide parameters for the execution of a function prior to the execution of that function. For example, when a function is to be provided as the first argument to the setTimout function that is common in web browser environments.
setTimeout schedules the execution of a function (or a string of javascript source code, but not in this context), provided as its first argument, after an interval expressed in milliseconds (as its second argument). If a piece of code wants to use setTimeout it calls the setTimeout function and passes a reference to a function object as the first argument and the millisecond interval as the second, but a reference to a function object cannot provide parameters for the scheduled execution of that function.
However, code could call another function that returned a reference to an inner function object, with that inner function object being passed by reference to the setTimeout function. The parameters to be used for the execution of the inner function are passed with the call to the function that returns it. setTimout executes the inner function without passing arguments but that inner function can still access the parameters provided by the call to the outer function that returned it:-
*/
function callLater(param){
/* Return a reference to an anonymous inner function created
with a function expression:-
*/
var localVar = 1;
return (function() {
/* This inner function is to be executed with - setTimeout
- and when it is executed it can read, and act upon, the
parameters passed to the outer function:-
*/
var calc = param + localVar;
console.log(calc);
});
}
var functRef = callLater(1);
setTimeout(functRef, 3000);
/*
------------------------------------------------------------------------------------
-------------------- USE AS AN ALTERNATIVE TO GLOBAL VARIABLES ---------------------
------------------------------------------------------------------------------------
*/
/* http://jibbering.com/faq/notes/closures/ */
/*
Closures can be used to create additional scopes that can be used to group interrelated and dependent code in a way that minimises the risk of accidental interaction. Suppose a function is to build a string and to avoid the repeated concatenation operations (and the creation of numerous intermediate strings) the desire is to use an array to store the parts of the string in sequence and then output the results using the Array.prototype.join method (with an empty string as its argument). The array is going to act as a buffer for the output, but defining it locally to the function will result in its re-creation on each execution of the function, which may not be necessary if the only variable content of that array will be re-assigned on each function call.
One approach might make the array a global variable so that it can be re-used without being re-created. But the consequences of that will be that, in addition to the global variable that refers to the function that will use the buffer array, there will be a second global property that refers to the array itself. The effect is to render the code less manageable, as, if it is to be used elsewhere, its author has to remember to include both the function definition and the array definition. It also makes the code less easy to integrate with other code because instead of just ensuring that the function name is unique within the global namespace it is necessary to ensure that the Array on which it is dependent is using a name that is unique within the global namespace.
A Closure allows the buffer array to be associated (and neatly packaged) with the function that is dependent upon it and simultaneously keep the property name to which the buffer array as assigned out of the global namespace and free of the risk of name conflicts and accidental interactions.
The trick here is to create one additional execution context by executing a function expression in-line and have that function expression return an inner function that will be the function that is used by external code. The buffer array is then defined as a local variable of the function expression that is executed in-line. That only happens once so the Array is only created once, but is available to the function that depends on it for repeated use.
The following code creates a function that will return a string of HTML, much of which is constant, but those constant character sequences need to be interspersed with variable information provided as parameter to the function call.
A reference to an inner function object is returned from the in-line execution of a function expression and assigned to a global variable so that it can be called as a global function. The buffer array is defined as a local variable in the outer function expression. It is not exposed in the global namespace and does not need to be re-created whenever the function that uses it is called.
*/
var getImgInPositionedDivHtml = (function(){
/* The - buffAr - Array is assigned to a local variable of the
outer function expression. It is only created once and that one
instance of the array is available to the inner function so that
it can be used on each execution of that inner function.
Empty strings are used as placeholders for the date that is to
be inserted into the Array by the inner function:-
*/
var buffAr = [
'<div id="',
'', //index 1, DIV ID attribute
'" style="position:absolute;top:',
'', //index 3, DIV top position
'px;left:',
'', //index 5, DIV left position
'px;width:',
'', //index 7, DIV width
'px;height:',
'', //index 9, DIV height
'px;overflow:hidden;\"><img src=\"',
'', //index 11, IMG URL
'\" width=\"',
'', //index 13, IMG width
'\" height=\"',
'', //index 15, IMG height
'\" alt=\"',
'', //index 17, IMG alt text
'\"><\/div>'
];
/* Return the inner function object that is the result of the
evaluation of a function expression. It is this inner function
object that will be executed on each call to -
getImgInPositionedDivHtml( ... ) -:-
*/
return (function(url, id, width, height, top, left, altText){
/* Assign the various parameters to the corresponding
locations in the buffer array:-
*/
buffAr[1] = id;
buffAr[3] = top;
buffAr[5] = left;
buffAr[13] = (buffAr[7] = width);
buffAr[15] = (buffAr[9] = height);
buffAr[11] = url;
buffAr[17] = altText;
/* Return the string created by joining each element in the
array using an empty string (which is the same as just
joining the elements together):-
*/
return buffAr.join('');
}); //:End of inner function expression.
})();
console.log(getImgInPositionedDivHtml('url', 1, 23, 50, 2, 3, 'alt text'));
/*
A global variable - getImgInPositionedDivHtml - is declared and
assigned the value of an inner function expression returned from
a one-time call to an outer function expression.
That inner function returns a string of HTML that represents an
absolutely positioned DIV wrapped round an IMG element, such that
all of the variable attribute values are provided as parameters
to the function call:-
*/
/* http://stackoverflow.com/questions/111102/how-do-javascript-closures-work */
function setupSomeGlobals() {
// Local variable that ends up within closure
// Acts as an emulated global variable.
var num = 666;
// Store some references to functions as global variables
getNumber = function() { return num; }
increaseNumber = function(x) { num += x; }
setNumber = function(x) { num = x; }
}
setupSomeGlobals();
console.log(getNumber()); // 666
increaseNumber(1);
console.log(getNumber()); // 667
setNumber(5);
console.log(getNumber()); // 5
var getOldNumber = getNumber;
setupSomeGlobals(); // reset emulated global variable
console.log(getNumber()); // 666
console.log(getOldNumber()); // 5
/*
The three functions have shared access to the same closure — the local variables of setupSomeGlobals() when the three functions were defined.
Note that in the above example, if you call setupSomeGlobals() again, then a new closure (stack-frame!) is created. The old getNumber, increaseNumber, setNumber variables are overwritten with new functions that have the new closure. (In JavaScript, whenever you declare a function inside another function, the inside function(s) is/are recreated again each time the outside function is called.)
*/
/*
------------------------------------------------------------------------------------
-------------------------------- OTHER EXAMPLES ------------------------------------
------------------------------------------------------------------------------------
*/
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
/*
the counter is now 3
The variable add is assigned the return value of a self invoking function.
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
This way add 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.
*/
function sayHello2(name) {
var text = 'Hello ' + name; // Local variable
var sayAlert = function() {
console.log(text);
};
return sayAlert;
}
say2 = sayHello2('Bob');
say2(); // writes "Hello Bob"
/*
The above code has a closure because the anonymous function function() { alert(text); } is declared inside another function, sayHello2() in this example. In JavaScript, if you use the function keyword inside another function, you are creating a closure. In JavaScript, if you declare a function within another function, then the local variables can remain accessible after returning from the function you called. This is demonstrated above, because we call the function say2() after we have returned from sayHello2().
*/
function foo(x) {
var tmp = 0;
return function (y) {
console.log(x + y + (++tmp));
}
}
var bar = foo(1); // bar is now a closure. (x)
bar(1); // 3 - (y)
bar(2); // 5 - (y)
bar(3); // 7 - (y)
/*
bar can still refer to x and tmp, even though it is no longer directly inside the scope. However, since tmp is still hanging around inside bar's closure, it is also being incremented. It will be incremented each time you call bar.
*/