JavaScript Closures

11:02 AM Xun 1 Comments

A lot has been said about and done with JavaSript closures. From the much technical and inner-mechanism oriented (and much recommended) article: Javascript Closures, to the highly accessible and simplified explanation at JavaScript Closures for Dummies, there is also very good run-down of use-cases at Use Cases for JavaScript Closures.

That JavaScript could have closure is because functions in JavaScript can be anywhere and anything, functions can be anonymous, self-evoking; functions can be passed as parameters, and returned as values. And when a function is returned from inside of another function, it has access to the variables in its parent scope. Thus it is said, that the function closes over / binds / remembers the environment from which it was created.


function HelloWorldClosure(){
var counter = 0;

var hello = function(){
counter += 1;
alert( "Hello World " + counter);
}

return hello;
}

var hello1 = HelloWorldClosure();
var hello2 = HelloWorldClosure();


So in the above, two closures are formed when two variables
hello1
and
hello2
are assigned to returned value of
HelloWorldClosure
. Now, we can call
hello1()
,
hello2()
as we would with any functions. Each call would increment the counter variable independently.

hello1();  // 1
hello1(); //2

hello2(); //1
hello2(); //2

hello1(); //3


Closures can be easily confused with regular inner functions. For example:

function HelloWorld(){
var counter = 0;

function (){
counter += 1;
alert( "Hello World " + counter);
}

hello();
}

HelloWorld();


When the outer function
HelloWorld
is called, it will simply create and initiate a new varible counter, then go through the chain of function calls, and execute
hello()
, and exit.


Multiple closures

Multiple closures can live inside one big outer functions, therefore share the environment. This can have unintended consequences.

For example:

function HelloWorldClosure(){
var counter = 0;

var hello = function (){
counter += 1;
alert( "Hello World " + counter);
}

var byebye = function(){
counter -= 1;
alert("bye " + counter);
}
return {hi: hello, bye:byebye};
}

var hello3 = HelloWorld();
hello3.hi(); //1
hello3.hi(); //2
hello3.bye(); //1


Why because hello and bye both are closures that have equal rights to the variable living in the parent function
HelloWorld
.


setTimeOut
and
setTimeInterval


SetTimeOut and SetTimeInterval take two parameters: 1) a function or a reference to a function as its first parameter; 2) the number of milliseconds to wait before excuting the code. The function passed to
setTimeout
/
setTimeInterval
is a closure, it has control over the variable in the environment.

        var counter = 0;

var incrementPerSec = function () {
console.log(counter);
counter = counter + 1;
};

setInterval(incrementPerSec, 1000);



Closures often means functions are stored and executed later. A inner function that is returned from an outer function does not get executed the outer function is called, it is only executed when the function itself is called. Therefore in the above example,

var hello3 = HelloWorld();
hello3.hi(); //1


Also in the
setTimeInterval
function, the function is stored and only executed after a set time.

Because of this delayed execution, closures can often get tangled with loops.

   for (var i = 0; i < 10; i++) {
setInterval(function () {
console.log(i);
}, 1000);
}



The above function will log a 10 (nothing but 10) every second. Because by the time the little function starts to log the i value, i has already finished its iteration cycle and stays put at value 10.

So how do you log the i value in a loop in a delayed fashion? One solution could be using a function that execute immediately to capture the i value.

  for (var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function () { console.log(i); }, 1000);
})(i);

}



So the above uses an self-evoking anonymous function in the form of
(function(){})()
. Turned out that it is frequently used to form a closure.


Closures everywhere

Once you noticed closures, you noticed them everywhere. For example, jQuery.

The first thing you notice about jQuery, in fact, a lot of libraries, is that it uses an anonymous function as the library wrapper.


(function() {
var jQuery = window.jQuery = function () {
//
};
// ...
};
}();



The anonymous function ensure the library, all of its variables and functions, is completely enclosed in its own environment.


jQuery
$(document).ready()


In jQuery, all calls are started inside the
$(document).ready
function. So by definition, all function calls are inner functions. And quite of the inner functions are closures. For example, the event binding functions in jQuery are all closures.

Take for example, the hover event.

//http://code.jquery.com/jquery.js
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}


and we use the hover function as such.

//http://api.jquery.com/hover/
$("li").hover(
function () {
$(this).append($(" ***"));
},
function () {
$(this).find("span:last").remove();
}
);



Not surprisingly, closures sometimes can collide over the variables in the environment.

                                                                  






Minus one: My value now is 10

Plus one: My value now is 10





AJAX Callbacks


AJAX callbacks uses closures to manipulate data outside of its scope.

$('#letter-b').click(function () {
var txtDiv = $("#bText").html("loading...");
$.ajax({
url: "data.html",
success: function (data) {
txtDiv.append(data);
}
});
return false;
});



JavaScript private and public members


Closure is what makes differenticated access control in JavaScript possible, that is, that is why JavaScript get to have "peudo-class" (objects) with private and public members.

The following uses the widely popular YUI module pattern.

YUI module pattern

 var Person = function(age, name){

var _age = age;
var _name = name;

return{
function getName(){
return _name;
}

function setName(){
_name = name;
}
}
}


The YUI module pattern is also rewritten as the following for the purposes of a) public and private members have the same coding style; b) the return section is less bloated and easier to read.

 var Person = function(age, name){

var _age = age;
var _name = name;
var getName = function(){
return _name;
}
var setName = function(){
_name = name;
}

return{
getName: getName,
setName: setName
}
}



Both use closures to seperate public from private members. From outside, only name can be get and set through privided methods:
getName
,
setName
.


var perter = new Person("peter", 30);

peter.setName("Person Johnson");

console.log(peter.getName()); // return "Person Johnson"

var mary = new Person("mary", 30);

//mary.setName("Person Johnson");

console.log(mary.getName()); // return "Person Johnson"



Source:

Javascript Closures
Use Cases for JavaScript Closures
JavaScript Closures for Dummies
JavaScript Closures for Dummies
Learning JQuery: Appendix: Closures
Learning JQuery: Appendix: Closures
Secrets of the JavaScript Ninja

1 comment: