Thursday, April 12, 2007

JavaScript closures

As Doughlas Crockford rightly puts it The world's most misunderstood language, the language has certain very powerful features like closure which is rarely nicely utilized.

I've recently started working in JavaScript and learnt few concepts and techniques on closure in the language. Lemme first start explaining what it is.

Closure formally seems to be a complicated definition. I would like to put it "Closure is a technique which lets you declare an inner function and access outer function's variable in it by storing the state of outer function".


function outer() {
var i = Math.random() * 10 + 1; // random num from 1 to 10
return function (a) {
return i + a;
}
}

var f = outer(); // returns a function and stores it in f
alert(f(2)); // calls f which magically has access to 'i' even though the outer has returned

this would output 3 (1 the random number + 2). Now the first thing comes in mind after seeing this is how can inner function access it when it doesn't exist! This is because our way of thinking in traditional language environments like C where a variable is defined when the function is called (typically on stack) and released after the function returns. Here, the function after returning remains in memory (say like an object remains in memory in an object oriented system).

In these kind of cases where an inner function is defined, the outer function along with its current variables are stored and it is linked to inner function. One can think of outer function to be like an object privately storing its local variables including variables passed as arguments. The inner functions are linked to this particular object.



As can be seen in the diagram each invocation of "outer" creates a separate object and stores its inner variable. The inner function has a link to this object. Rather ONLY inner function has link to this object (function). Hence, when no variable is referencing the inner function, the inner function along with "outer" is garbage collected. If a function defines two inner functions both the inner functions have link to that copy of outer function. Guess thats why this technique is called "closure" as the inner function is closed on an environment which is the instance of outer function.

Now, I would like to share an incident which made me visualize closure better than earlier. I was writing code where I had to create functions based on data from an array.


function createFuncs(arr) {
for (var i = 0; i < arr.length; i++) {
var data = arr[i];
window[data.name] = function() {
// do something with 'data'
var s = data.some;
}
}
}


As you can see, I am trying to create functions on window object (window is the top level JavaScript object in browser environment) hence, writing something like window["func"] = function() {...} will create a function which can be directly invoked (like func(a)). This is how alert and other functions are. The function name and its working is based on "data". I would expect that each function works on its separate "data" when called, i.e. say func0 (from say data.name) would work on arr[0], func1 on arr[1] and so on. But I was wrong.. Turns out that all the funcs when invoked end up working on arr[arr.length - 1] (i.e. last element of the arr). This is because "data", a variable declared inside loop doesn't have block scope, it has function scope. When the loop finishes data refers to last element of array. All the functions created have link to the same function "createFuncs". Hence, when called they refer to one "data" variable which at that time refers to last element arr.

Well, this is not what I wanted. What to do? Then it just struck me that instead of closing created functions on createFuncs, I can close it on another function which has its required "data". So, I ended up doing something like this :)


function createFuncs(arr) {
for (var i = 0; i < arr.length; i++) {
var data = arr[i];
var createFunc = function(data) {
window[data.name] = function() {
// do something with 'data'
var s = data.some;
}
}
createFunc(data);
}
}


Now, every call to "createFunc" creates a instance of "createFunc" (the word instance may not be right but its the best I could fit in this situation) which has that "data" at that time and newly created function is bound to this "createFunc" and hence its "data".

Thats it folks.. Please do leave your comments on anything about the article :)

3 Comments:

Blogger Mike Griffiths said...

Closures are a cool feature of the World's coolest language (JavaScript) but watch out for the memory leaks.

7:35 AM  
Blogger roshan said...

aalloo, you totally kicked ass, them closures will never scare people any more! I think you should submit this to slashdot. Them monkeys from school won't get it anyways. :)

On a more serious note, ask DJ to have a look at this.

9:03 AM  
Blogger Bosky said...

Maybe you can add an additional optional event argument (e) to createFunction ? im sure it could be useful to have the event argument seperate from the rest in case it needs to be passed on.

Keep Clicking,
Bhasker

12:27 AM  

Post a Comment

<< Home