Sunday, March 1, 2009

How 'closures' work in Javascript (and Perl)

When I was learning Perl, the concept of a "closure" was one of the more difficult for me. And the first time around, I didn't really get it. So, I put it aside for later and didn't really use them. It then promptly fell to the bottom of the pile and slipped through the cracks. I later started writing a lot of Javascript and re-encountered closures. This time, I was determined to understand what they are and how they work.



I'm glad I did, because they can be very useful when one gets into a coding bind. It also allows for implementation of "private" object members or variables in very open, unrestrictive languages like Javascript and Perl.

The truth is, it's very simple. This is one of those things that sound complicated because of the confusing way that it's presented by people who are too smart for their own good. They use words like "context" and "closure". Why they can't just say "scope" is beyond me...

At any rate...

A closure is just a fancy little trick with scope.

An Example of a Javascript Closure

A simple example should clear everything up. In the following code, we run an anonymous function that displays the value of 'foo'. The variable 'foo' is local to that function, so when the function ends, the variable is destroyed. Outside that function, the variable is out of scope. This should make sense to anyone with basic programming knowledge.
// Anonymous function
function showFoo() {
   var foo = 10;  // foo in a closure
   alert( foo );
}

showFoo();     // shows '10'

alert( foo );  // ERROR

We could just move foo outside the scope of the function and make it a global variable, and everything would be honkey-dory. But maybe we don't want it to be a global that can be set to any value from any code. Javascript doesn't have 'const' variables. If we don't want code outside this function to be able to change foo, but we still want to be able to get it, then we put it in a "closure".

We just define another function in the same scope as foo. A function can be assigned to a variable just like any other value, so assigning the getter function to a global makes it callable from the outside:

// Anonymous function
var getFoo;  // function for getting foo
(function() {
   var foo = 10;  // foo in a closure

   alert( foo );  // shows '10'

   getFoo = function() {
      return foo;
   }
})();

alert( getFoo() );  // shows '10'


The scope of a Javascript function will always be the scope in which it was defined. So, because the getFoo function was defined in a scope where foo was visible, it will always be able to see foo, even if it's being called from another scope.

Now you've created a closure! Simple, eh? This can be used to do fancy object-oriented things like getters, setters, private object members, and so on, and so forth in a programming language that doesn't support those things natively.

Hope this helps!

No comments: