Knowledge for the World

JavaScript closures by example

Closures are extremely valuable if you know how to use them. The problem is that many JavaScript developers don't know how to use them. After reading this guide I hope you will have a good grasp of what a closure is, how it works, and when to use them.

In these interests [?]
  • code
    110 Subscribers Subscribe
  • webdev
    124 Subscribers Subscribe
  • javascript
    82 Subscribers Subscribe
1

What is a closure?

According to MDN, Mozilla Developer Network, "Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created. "

Take this example:

var outerFunc = function() {
    var message = "Hello, World!";
    var innerFunc = function() {
        return message;
    }
    return innerFunc;
}

You should be aware that JavaScript implements function level scoping, not block level scoping as you may find in some other languages. So in our example above, variables defined within outerFunc are local to that function's scope - meaning you can't access them outside of the function. And typically, when a function is finished executing it's local variables no longer exist.

But the above code is interesting because our outerFunc function is returning innerFunc that refers to a local variable. So do you expect the message variable to be available even after outerFunc has finished executing?

> var myFunc = outerFunc();
> myFunc();
'Hello, World!'

It absolutely is. As you can see, outerFunc executes returning innerFunc which is stored in the variable myFunc. myFunc becomes a closure so it remembers the environment in which it was created. It remembers the value of the message variable at the time outerFunc was executed. Chances are you've been using closures without knowing it!

2

For loops: a common mistake

At some point you may have run into a problem when executing functions from within a for loop. The first time it happened to me I almost gave up programming to be a lumberjack.

Take a look at this example:

var names = ['Locke', 'Franklin', 'Smith', 'Mises'];
var logName = function(name) {
    console.log(name);
};
var name;
for (var i=0; i < names.length; i++) {
    name = names[i];
    setTimeout(function(){
        logName(name);
    }, 1000);
}

In the code above, we've created an array called names to store a list of four names and we've written a logName function that takes in a single name as a parameter and logs it. Then we've created a for loop to iterate through our list of names, set a 1 second timeout, and then call our logName function passing in the current name. You may think this contrived example would work, but it will actually log "Mises" four times.

The reason for this is quite simple. logName is a closure that remembers the environment in which it was created. If you called logName directly from the for loop it would work and print out all names. But instead we're setting a timeout, creating a closure (the callback to setTimeout), and this closure is remembering the environment. By the time our one second timeout expires, the name variable has been set to "Mises". So it simply logs "Mises" four times.

How can we fix this? One way to fix this is by implementing another closure.

var names = ['Locke', 'Franklin', 'Smith', 'Mises'];
var logName = function(name) {
    console.log(name);
};
var makeClosure = function(name) {
    return function() {
        logName(name);
    }
};
for (var i=0; i < names.length; i++) {
    var name = names[i];
    setTimeout(makeClosure(name), 1000);
}

This certainly isn't beautiful, and it isn't good to create unnecessary closures. In fact, there are much better ways to accomplish this particular result, but I wanted to demonstrate the problem with closures in for loops, and how a closure can fix it. If you run the code above, you'll see that it works as expected, logging each of the four names after a one second delay. What we had to do was create a makeClosure function that returns a closure 'remembering' the name variable from when it was created. The closure is created instantly so it remembers the value of each name.

3

The module pattern

Many developers use the module pattern which is based on JavaScript closures. You can read more about the module pattern in depth here, but I'm going to cover the basics and how it implements closures.

The purpose of using the module pattern is to organize code, keep the global scope clean, and keep private code that shouldn't be accessible from outside of the module.

The module pattern looks like this:

var module = (function(){
    var localVar = 1913;
    var localFunc = function() {
        return localVar;
    }
    var otherLocalFunc = function(num) {
        localVar = num;
    }
    return {
        getVar: localFunc,
        setVar: otherLocalFunc
    }
})();

Here we are creating a single environment inside of an anonymous function. This environment contains a local variable localVar and a local function expression localFunc. Neither of these variable names are accessible from outside of our anonymous function thus keeping the global namespace clean. In order to access anything from outside our anonymous function, it needs to be return by the anonymous function. As you can see in our example, we are returning an object with a key of getVar that is set to the value of localFunc and another key of setVar which is set to the value of otherLocalFunc. The beautiful thing about this pattern is that the state of the module persists throughout the life of our application. By this I mean that even though localVar is not directly accessible from the outside, the functions we return still has access to this variable. Take a look at this example utilizing the code from above:

console.log(module.getVar());
> 1913
module.setVar(1776);
console.log(module.getVar());
> 1776

We've successfully emulated a private variable, localVar, in JavaScript. We've kept the global namespace clean, the only global variable here is module. And we've done this all using a closure.

Although this is not part of the scope of this guide, this pattern depends on an IIFE (immediately invoked function expression). You'll notice that the anonymous function is wrapped in parenthesis like this (function() { ... })(). Without the parenthesis, this would simply be a function definition. But adding the parenthesis (notice the trailing parenthesis as well) causes this to become a function expression that is invoked immediately. Read more about this here.

4

Another example

Here's a more practical example. Suppose we want to create functions on the fly. We can create a function factory - a function that makes functions. The resulting function from the function factory will be a closure that remembers the environment that it was created in.

var functionFactory = function(num1) {
    return function(num2) {
        return num1 * num2;
    }
}

The above allows us to pass in a single number to the functionFactory. Then the functionFactory returns a closure that remembers the value of num1 that was originally passed in. The resulting function multiplies the original num1 times the value of num2 that is passed in upon invocation.

var mult5 = functionFactory(5);
var mult10 = functionFactory(10);

The above simple creates our new functions mult5 and mult10. We can now invoke either of these functions passing in a new number that we want to multiply by 5 or 10. By now you should be able to anticipate the outcome.

> mult5(3)
15
> mult5(5)
25
> mult10(3)
30
> mult10(5)
50

If you found this guide useful, let me know below. Also please comment if you found an error and especially if you can provide more unique examples.