Thursday, August 6, 2009

Javascript Closures - A very basic explanation



This article will explain Javascript Closures and will approach this by first explaining what inner functions are and how variables from their outer functions are accessible by them. It is assumed the reader has a basic knowledge of Javascript and how to write their own javascript functions, as well as how to pass in variables to functions and how local variables work. If not I recommend going through the Javascript tutorial at W3Schools. Starting with the basics, an inner function is a function defined and written within the body of another function, a simple example is below.




function outerfunc(){



function innerfunc(){


var b=2;

alert("b is " + b);


}


innerfunc();


}



outerfunc();



The code above will simply display "b is 2", in a windows alert box and the code is intentionally simple. innerfunc() is defined inside of outerfunc() and is also called from within outerfunc(). innerfunc() in this context is accessible only within outerfunc() since innerfunc() is essentially a local variable that references a function, and local variables are private to the functions they are written in. Let's modify the above function a bit.



function outerfunc(){



var a = 5;


function innerfunc(){


var b=2;

alert("b is " + b);

alert("a is " + a);



}


innerfunc();



}



outerfunc();



Now we have added a declaration and assignment for variable "a" within outerfunc(). When the code is executed 2 alert boxes come up. The first box displays "b is 2", the second alert box displays "a is 5". What this demonstrates is that when a function is defined within another function it has access to the outer function's variables. To drive this point home, here is another code example.



function incrementtwice(){



var a = 1;


function incrementandshow(){


a += 1;

alert("a is " + a);



}


incrementandshow();

incrementandshow();



}



incrementtwice();



When the code above is executed 2 alert boxes come up. The first box displays "a is 2", the second alert box displays "a is 3". So in a nutshell, and to reiterate, an inner function has access to variables defined in outer functions. But remember that outer functions do not have access to variables defined in inner functions. For example




function outerfunc(){



var txt = "testing";


function innerlevel1(){



function innerlevel2(){


alert(txt);



}

innerlevel2();


}

innerlevel1();


}



outerfunc();



The code above will display an alert box that displays "testing". First from outerfunc() we call innerlevel1(), and we can not call innerlevel2() from within outerfunc() because innerlevel2() is a local function of innerlevel1(). So we call innerlevel2() from innerlevel1(). Now what is important here to note is that innerlevel2() has access to the variable "txt" which is defined in outerfunc(). innerlevel2() has access to any variables it defines, any variables innerlevel1() defines, any variables outerfunc() defines, and of course any global variables. Now we'll get to something a little more interesting. Take a look at the code below.




function getincrementer(){



var a=0;

function incrementa(){

a++;


}



return incrementa;
}




var bul = getincrementer();

var bul2 = getincrementer();



alert("bul is " + bul());

alert("bul is " + bul());

alert("bul2 is " + bul2());




The above code when run will show alert boxes displaying "bul is 1", "bul is 2", and "bul2 is 1". We make 2 calls to getincrementer(). getincrementer() returns a reference to the inner function incrementa(), which increments variable "a" defined in the outer function. The variables "bul" and "bul2" are assigned references to the inner function incrementa() and have access to the variable "a" that is defined in getincrementer(). 2 things to note here, when an inner function is returned from an outer function the outer functions local variables and their values are retained, and each time the outer function is called a new and seperate instance of those local variables is created. For this reason the following code




var bul = getincrementer();

var bul2 = getincrementer() ;

creates it's own copy of the variable "a" for each call to getincrementer(). So, because of this when we call bull(), it increments it's own copy of the variable "a", and this does not affect "bul2" because it too has it's own copy of the variable "a". Now let's alter getincrementer() a tad by passing a variable into it and having the inner function increment the passed in variable instead.

function getincrementer(theval){



function incrementa(){

theval++;

return theval;

}



return incrementa;
}



var bul = getincrementer(1);
var bul2 = getincrementer(10);


alert("bul is " + bul());
alert("bul2 is " + bul2());



The code above would display 2 alert boxes, the first showing "bul is 2", the second showing "bul is 11". Variables passed into the outer function also retain their values when a reference to an inner function is returned. Finally a simple definition of a Javascript Closure is - A reference to an inner function and the local variables and parameters of the enclosing outer function, or functions if nesting is used.


Related links:




JavaScript Closures 101- they're not magic
. Written by Morris Johns. This is a good basic introduction to closures and is in fact where I started in learning them.



JavaScript Closures. Written by Richard Cornford. March 2004. A much more detailed and technical definition of closures that I highly recommend.


Animated Flickr Collage - Google Gadget

I have created a google gadget that allows a user to create a collage of photos that animate much like a slide show. The table can be as small as 1x1, which is basically just a clickable slide show, or up to 2x2. Images are loaded into memory from Flickr based on search tags given. Then pics in the table are swapped out based on a timer, and replaced with an image in memory. Images can be clicked and then a separate window is opened that accesses the picture on Flickr. To open a window with text boxes and menus, that mimic the gadget, and displays the animated table click here. The path for the url is http://jimlaurino.hostzi.com/gadgets/animflickrtablegad.xml. At present 6 languages are supported - english, spanish, german, french, italian, and hindi. My native language is english and I am not multilingual, so I used http://imtranslator.com/ to support other languages. It was written using the Gadgets.* API and I've tested it in igoogle and blogger. To use the gadget in igoogle or blogger just use the add gadget by url feature and use the url path listed above. Or you can log into your google account and click the button below to add to igoogle.

Add to Google
 
My Zimbio
Top Stories