Closures Shmosures

Ever heard those javascript snobs talk about closures? "Closures" they'll say "are one of the most powerful concepts in javascript, but they can cause a lot of problems (like memory leaks) if you don't know what you're doing."

I say PHOOEY! Throw caution to the wind and use closures. Personally, I think the warning against closures is just so the javascript elite can continue to feel "elite." No one can dispute the benefits of closures; they're just way too convenient not to use. And anyone who throws the "memory leak" excuse at you is probably referring to IE6's well know memory leak problems (and we can only hope that IE7 will resolve those issues).

So obviously I'm going to talk about closures, but for the sake of simplicity, I want to only focus on one specific technique that involves closures: passing object parameters to a setTimeout(..) function. Read on to learn more.

The setTimeout(..) function is a handy little thing. This function, along with its brother, setInterval(..), are what make things like animating DOM elements possible in javascript (among other things of course).

If you're not familiar with how setTimeout(..) works, here is a brief refresher. You have two basic options:


setTimeout(strExpr, nMillisec);

Where strExpr is a string value that is to be evaluated after nMillisec milliseconds.

Your other option for using setTimeout is as follows (the differnce is subtle):


setTimeout(fnPointer, nMillisec);

Where fnPointer is a pointer to a function that should be executed after nMillisec milliseconds. Note that you should not include parenthesis when passing in the function pointer. Otherwise it will attempt to execute the function immediately instead of waiting nMillisec milliseconds.

This obviously begs the question then… how DO you pass a parameter to that function you want to execute after nMillisec milliseconds?

Well, it all depends on what type of parameter it is you want to pass. If the parameter is a string or a number (that can be represented as a string), then you can simply concatentate the proper string and use the first setTimeout(..) function (the one that takes a string instead of a function pointer). For example:


function add(n1, n2)
{
   alert(n1 + n2);
}

var a = 7;
var b = 10;
setTimeout('add(' + a + ', ' + b + ');', 1000);

The preceding code will make a call to add(7, 10) after 1 second. This works fine if the parameters you want to pass are of a type that can be logically concatenated into a string.

But suppose you have a custom object, say a Person object that you've created:


function Person(name, age, isSmart)
{
  this.Name = name;
  this.Age = age;
  this.IsSmart = isSmart;
}

And now suppose you have a function, sayHello(..) which takes a Person object as a parameter. If you tried to concatenate a Person object in a string like 'sayHello(' + somePerson + ');', it doesn't take a genius to figure out that that isn't going to work.

And if you tried to call the function without quotes (so that it did not get interpreted as a string) and with parenthesis as in sayHello(somePerson); it would execute the function immediately instead of 1 second later (and in IE you'd get the added bonus of an error).

The answer? Why, closures of course (you had to expect that by now).

Perhaps now is a good time to briefly explain exactly what a closure is. Put quite simply, a closure is a technique that allows you to access variables that would (under normal circumstances) be out of scope and inaccesable.

An example using our Person object and sayHello(..) function will help illustrate this more clearly.


function Person(name, age, isSmart)
{
   this.Name = name;
   this.Age = age;
   this.IsSmart = isSmart;
}

function sayHello(person)
{
   var msg = 'Hi #name#!  You are #age# and our records indicate that you are #issmart# very smart.'

   msg = msg.replace(/#name#/, person.Name);
   msg = msg.replace(/#age#/, person.Age);
   msg = msg.replace(/#issmart#/, person.IsSmart ? " : 'not');

   alert(msg);
}

function sayHelloProxy(person)
{
   return function()
   {
      sayHello(person);
   }
}

var steve = new Person('Steve', 26, true);
var chandu = new Person('Chandu', 80, false);

setTimeout(sayHelloProxy(steve), 1000);
setTimeout(sayHelloProxy(chandu), 2000);

The piece that needs explanation here is the sayHelloProxy(..) function. This is where the closure is actually created. The first time you try to process this, it usually takes a few minutes before it makes sense, so don't feel bad if what's going on here isn't immediately obvious. Here's the scoop:

The function, sayHelloProxy(..) takes one parameter which we've named person. The function itself however, doesn't do much except return another function! "What the…" (I can hear at least half of you saying).

Sure! One function returns another function. There is no problem here. A function can return a string, an integer, a boolean… why not another function?

Buy why would you want to do this? Closures! (there's that word again). Returning the lambda function (fancy name for an anonymous function) inside of the sayHelloProxy(..) function creates a closure. This means that we have access to all of sayHelloProxy's parameters inside of the the lambda function, even after sayHelloProxy(..) finishes and has long been out of scope!

Therein lies the magic of closures. If sayHelloProxy(..) is finished executing, its local variables should be destroyed, out of scope and inaccesable. And they are… sort of. They're out of scope for every piece of your script except for the lambda function you used to create the closure.

Pretty cool if you ask me, but I feel I'd be doing a disservice if I didn't at least briefly mention that some of those javascript snobs might have a teeny weeny point when they bring up the topic of memory leaks. It's important to realize that closure are not the only way to create memory leaks, but they are one of the most common, albeit inadvertendly (I hope).

Since I'm not really interested in writing a javascript post about memory leaks (at least not right now), I will instead suggest that you simply google "javascript memory leaks ie" or something like that and do a bit of learning before diving too deeply into techniques involving closures.

Yes, yes, I know that it's pathetic how little information I provide about memory leaks above, but c'mon! Memory leaks just need to simply go away. It's ridiculous that javascript programmers should have to waste their time coding "around" this issue (especially since ECMAScript language specifications mandate that the languge should have automatic garbage collection). If a certain development team that is responsible for a certain web browser would simply get their act together and address the issue, I wouldn't even need to write this little side note.

But I digress.

Hopefully with this post, you've at least seen the power that closures can offer. Resources on javascript closures are plentiful on the web, so I'd encourage you to do some search and read up a bit. Once you start using them in your scripts, you'll wonder how you ever got along without them.

Comments welcome.

Got something to say?

Please note: Constructive criticism is welcome. Rude or vulgar comments however, are not and will be removed during moderation.