featured

By Matt MerkesApril 17, 2014

Closures: The 'ringers' of JavaScript

How do closures work? This post helps the JavaScript noob understand closures a little better.

If you were to learn everything that you learned about programming through Wikipedia, this is what you’d learn about closures:

A closure (also lexical closure or function closure) is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables or upvalues) of that function. A closure—unlike a plain function pointer—allows a function to access those non-local variables even when invoked outside its immediate lexical scope.
- Closure (Computer Programming), Wikipedia

I don’t know about you, but that’s making my noob head hurt (probably due to a lack of a CS degree), and I don’t feel any closer to understanding what a closure is. In fact, there’s a lot of not very helpful explanations of closures on the web, and my goal is to write a useful one. A lofty goal, but a noble one.

What’s my definition of a closure? Please don’t share this with any computer scientists as this is not a textbook definition, but a working definition that I think can help noobs understand what closures are:

A closure is a function within a function that has access to the environment that it was created, which gives it access to variables of the parent function. In JavaScript, a closure is often referred to a function returned by another function. They’re often called inner functions.

Don’t worry if you’re still lost. We’re going to go into examples. Let’s look at the function secretClub:

function secretClub() {
    // Please don't tell just anyone the passwords!
    var secretWords = [ 'cheetah', 'filthy', 'salinger'];

    return function( password ) {
        // Take secretWords and see if the array has a match for password.
        // If it doesn't, it will return the index, and we'll welcome them. 
        // If password is not in the array, we'll return -1 
        // and tell them to beat it!
        if ( secretWords.indexOf( password ) !== -1 )
            console.log('Welcome back!');
        else
            console.log("Nice try, but we don't just let anybody in!");
    }
}

Looking at this code, you can see that the anonymous function function( password ) is a closure. It has special access to secretWords that can be used outside of secretClub. secretWords is hidden, or encapsulated, so nobody besides the closure can access the variable on the outside.

For example, if you declare secretClub inside of your console, you’ll see that typing in secretWords returns a reference error, so it’s not in the global scope. If we type in secretClub.secretWords, it just returns undefined. However, we know that secretClub returns a function, so we can get access via the closure!

var theBouncer = secretClub();

Maybe we can access secret words through theBouncer!

theBouncer.secretWords
// Doh! returns undefined  

However, we can utilize the secret words list (even if we can’t peek at it) though the access is restricted to that variable. The only way in is through theBouncer!

theBouncer('bieber');
// logs "Nice try, but we don't just let anybody in!"

theBouncer('salinger');
// logs "Welcome back!"

Notice how we’re using theBouncer like it’s a function! Well, it is! The anonymous function from secretClub is returned and theBouncer references that function. This can be a real lifesaver when you’re trying to protect data or make sure that you’re not being overrun by variables. Also, when you’re using closures, they merely referencing the variables from the parent environment, so you’re not recreating the variables every time you fire the function. Look at this case:

function secretClub( password ) {
    var secretWords = [ 'cheetah', 'filthy', 'salinger'];

    if ( secretWords.indexOf( password ) !== -1 )
        console.log('Welcome back!');
    else
        console.log("Nice try, but we don't just let anybody in!");
    }
}

In this case, it’s creating secretWords every time you call secretClub rather than just referencing it. You may not know why that’s not preferable, but you know it isn’t.

Now, maybe the noob isn’t fully convinced that closures are the real ringers in JavaScript yet, but there’s more! In the last case, a closure is more code, but closures can also be used to write less code. Let’s take a look at this function:

function greetFamily( familyName ) {
    return function() {
        // Take any arguments passed into the anonymous function, slice
        // the arguments into an Array, and join the elements into a string with ', '
        var peeps = Array.prototype.slice.call(arguments).join(', ');
        // greet the lovely family
        console.log("Welcome to the holiday party, " + peeps + " " + familyName);
    }
 }

In this case, we have a function that takes a family name as an argument, and returns a closure that will greet everyone in the family! If we just typed greetFamily(‘Merkes’) into the console, it wouldn’t do anything except print the inner function. However, if we work some more closure black magic:

var greetMerkes = greetFamily( 'Merkes' );

We have a greeting for every group that comes to Christmas! If I call greetMerkes and pass it some names, it will remember that ‘Merkes’ is the familyName and do what it’s supposed to do:

greetMerkes('Matt', 'Rebekah', 'Archie', 'Ruth');
// logs "Welcome to the holiday party, Matt, Rebekah, Archie, Ruth Merkes"

The greetFamily function could be replicated to greet any family name and be recycled for further use.

The stereotypical example for closures is an adder function:

function adder ( x ) {
    return function ( y ) {
        return x + y;
    }
}

var add20 = adder( 20 );

add20( 3 );
// returns 23

As you can see, it works the same way. It creates a function that takes an argument for x and returns a function that takes an argument for y, which returns the result of adding x and y. Not rocket science, but it’s a slick demonstration of how closures could be used.

I hope that closures are a little clearer. The only way to get more comfortable with them is to practice, though this hardly scratches the surface of what closures can do. A lot of JavaScripters don’t understand closures all that well (or so I’m told), so keep at it! Here’s some more reading material if you want to know what MDN has to say about closures. In a future post, I hope to go over some more sophisticated examples as you move out of noobhood. Stay tuned!

Check out the original post and more resources on Matt’s blog, Noob.js.