Everything You Need To Know About JavaScript Closures

Posted by TotalDC

In this article, we will learn about JavaScript Closures. JavaScript variable’s scope can be global or local. A global variable can be accessed and manipulated anywhere in the program, while the local variable can only be accessed and manipulated by the function they are declared in.

There are situations when you want a variable to be available through the script, but perhaps you don’t want or need any part of your code to be able to change its value accidentally.

Here’s an example of what happens if you try to do this with with global variable:

// Global variable
let counter  = 0;

// A function dedicated to manipulate the 'counter' variable
function makeCounter() {
    return counter += 1;
}

// Calling the function
makeCounter();
console.log(counter); // Result: 1

makeCounter();
console.log(counter); // Result: 2

// Trying to manipulate the 'counter' variable from outside
counter = 10;
console.log(counter); // Result: 10

As you can see in the above example, the value of the counter variable can be changed from anywhere in the program, without calling the makeCounter().

Now, here’s the same thing with the local variable:

function makeCounter() {
    // Local variable
    let counter  = 0;
	
    // Manipulating the 'counter' variable
    return counter += 1;
}

// Calling the function
console.log(makeCounter()); // Result: 1
console.log(makeCounter()); // Result: 1

As you can see, the counter variable can’t be manipulated from outside, since it is local to makeCounter() function. But its value will not increase after a function call, because every time you call the function it resets the counter value.

A closure is an inner function that has access to the parent function’s scope, even after the parent function has finished executing. This is accomplished by creating a function inside another function. Let’s take a look at the following example to see how it works:

function makeCounter() {
    let counter = 0;
	
    // Nested function
    function make() {
        counter += 1;
        return counter;
    }
    return make;
}

/* Execute the makeCounter() function and store the
returned value in the myCounter variable */
let myCounter = makeCounter();

console.log(myCounter()); // Result: 1
console.log(myCounter()); // Result: 2

Here the inner function make() is returned from the outer function makeCounter(). So the value of the myCounter is the inner make() function, and calling myCounter effectively calls make(). In JavaScript, functions can be assigned to variables, passed as arguments to other functions, can be nested inside other functions, and more.

The inner function make() can access the value of the counter variable defined in the outer function, even when makeCounter() function has already finished executing. It happens because functions in JavaScript form closures. Closures internally store references to their outer variables and can access and update their values. In the example above, the make() function is a closure whose code refers to the outer variable counter. This implies that whenever the make() function is invoked, the code inside it can access and update the counter variable because it is stored in the closure. Since the outer function has finished executing, no other part of the code can access or manipulate the counter variable. Only the inner function has exclusive access to it.

How To Create The Getter And Setter In JavaScript

In this example, we will create a function and protect it from being directly manipulated from outside using closure. Then we will create getter and setter functions to get and set its value :

let getValue, setValue;

// Self-executing function
(function() {
    let protected = 0;
    
    // Getter function
    getValue = function() {
        return protected;
    };
    
    // Setter function
    setValue = function(x) {
        if(typeof x === "number") {
            protected = x;
        }
    };
}());

// Calling the functions
getValue(); // Result: 0
setValue(10);
getValue(); // Result: 10
setValue(null);
getValue(); // Result: 10