A little bit about JavaScript closures

JavaScript closures are rather difficult to understand until you get the hang of them. Here’s one little snippet that may help introduce them and their advantages, though.

Douglas Crockford has said:

This pattern of public, private, and privileged members is possible because JavaScript has closures. What this means is that an inner function always has access to the vars and parameters of its outer function, even after the outer function has returned. This is an extremely powerful property of the language. 

I like writing powerful code, myself. So here’s a short bit to demonstrate:

var add = (function() {
  stuff = [];
  return function(thing) {
    stuff.push(thing);
    return stuff;
  };
})();

So what’s happening here? To a new JavaScript coder, it might look like add is being set equal to a function. But in fact, it’s being set to the return value of that anonymous function. By wrapping the function in (...)(), we’re telling the JavaScript engine to take the function and run it immediately.

What’s the return value, then? Well, it’s another function — in JavaScript, functions are just another kind of object, which can be passed around as needed. Whenever you see a callback function in jQuery, that’s an anonymous function object being passed as an argument into some other method.

That inner function is what takes the argument thing and pushes it onto stuff, and then returns the value of stuff. And here’s where it gets interesting….

Because of how JavaScript scopes variables, stuff is only accessible to the outer anonymous function and anything inside of it — including the inner function. It can’t be accessed directly, no matter how hard you try.

Even after the outer function has run and returned the inner function, the inner function can continue to modify stuff as if it were a global variable. But nobody else can — stuff acts like a private variable now.

So if we run the above code sample in our browser’s JavaScript console, and use it, we get to see stuff being modified by the add function:

> add(1)
[1]
> add(2)
[1,2]

This gets a little more useful if you rewrite things so that add is a method to another function:

test = (function() {
  stuff = [];
  return { 
    add: function(thing) {
      stuff.push(thing);
      return stuff;
    }
  }
})();

And now test is an object with an add method:

> test.add(1)
[1]
> test.add(2)
[1,2]

Which is even more useful, because we can create additional methods inside that object, all of which have complete access to stuff without giving any other code on the page direct access to it.

Leave a Reply

Your email address will not be published. Required fields are marked *

*