Understanding Closures in JavaScript

Understanding Closures in JavaScript

Closures are one of those things we have to understand at some point in our JavaScript learning journey. Understanding them will help us become better JavaScript developers and write better code. But unfortunately, for some people it's not that straightforward. So in this tutorial, I'll try to make it as easy for you as I can.

Let's review scopes first

Understanding variable scopes is the key to understanding how closures work. As with all languages, there should be some way to define a scope for variables. You can think of a scope as the places in the code where you can access a certain variable.

The way scopes are defined differs from language to language. For example in Java, you define scopes by surrounding a piece of code with curly braces.

For example (in Java):

public static void main(String[] args) {
    { // beginning of a scope
        int a = 5;
    } // end of a scope
    
    int b = a + 2; // Error: variable a is not defined! (out of scope)
}

This is called a block-scoped variable. This is the case in Java and other languages. However, as you know this won't work in JavaScript.

JavaScript is a function-scoped language

In JavaScript new scopes are defined within functions. For example:

// Global scope

var glob = 3;

function outerFunction() {
    // A new scope
    var bar = 4;

    {
        // Not a new scope (unlike Java)
    }

    function innerFunction() {
        // Another nested scope
        var baz = bar + glob;
        console.log(baz); // 7
    }

    console.log(baz); // baz: is not undefined
}

In the preceding code, we have three scopes: the global scope, and two local scopes (inside outerFunction and innerFunction).

The only remaining thing we have to know is how scopes access each other. Here's a simple rule: only inner scopes can access outer scopes, not the opposite.

So in the previous example, the global scope can only access variables in its scope. However, the scope of outerFunction can access both, its own variables and the global scope's variables. And so on.

Show me closures!

Simply, you get a closure when you return a function or an object from another function — let's call it the outer function. The returned function/object will still have access to the variables that were defined within the outer function scope.

Not clear yet? Here's an example:

function outerFunction() {
    var a = 3;

    return function innerFunction(b) {
        var c = a + b;

        return c;
    }
}

We have a function called outerFunction(). In that function we have a nested function called innerFunction(b), which accepts a parameter called b.

When you invoke the outerFunction, you'll get the innerFunction returned — which you can later invoke.

Like this:

var foo = outerFunction();
// foo contains the innerFunction as an expression

Now let's call foo and give it a parameter of 2.

var result = foo(2);
console.log(result); // 5

Can you see something weird happening here? Even after the outerFunction was called, the variable a still has its value, 3, which we used in the returned function innerFunction.

This is what we call a closure!

It's called a closure because it closes over the free variables of the function it was returned from.

Another example

Let's see another example of how closures can be used.

function makeCalculator(a) {
        
    // private section

    var value = a || 0;
        
    // public section
    return {
        add: function(b) {
            value += b;
        },

        sub: function(b) {
            value -= b;
        },
        
        result: function() {
            return value;
        }
    }
}

var calc = makeCalculator(2); // initial value = 2
calc.add(2);
calc.sub(1);

console.log(calc.result()); // 3

Closures allow us to define private data

In the previous example, the property value is private. This means we can't access it directly from the outside. Instead, we have to define a public method that returns it — in this case it is the result() method.

This is what we call encapsulation! As you might know, encapsulation is one of the most important features of object-oriented programming. But JavaScript doesn't support that explicitly. However, with the help of closures, we can do just that! So thanks to Closures!

Closing

So in a nutshell:

A closure is a function plus the connection to the scope in which the function was created.

I hope it was an easy-to-understand tutorial. If it's still not clear, though, don't hesitate to ask any questions you have in the comments section.

JavaScript
Taha Shashtari

About Taha Shashtari

I'm a freelance web developer. Laravel & VueJS are my main tools these days and I love building stuff using them. I write constantly on this blog to share my knowledge and thoughts on things related to web development... Let's be friends on twitter.