Kunal Mhatre's Blog

JavaScript - Closure come with powers

October 28, 2019

I might be late to the party, but I must admit that Douglas Crockford came up with an awesome book on JavaScript. I am talking about JavaScript: The Good Parts. After ending up with the book, I learned two very useful and interesting ways in which we can use closures, and this blog post is all about that.

Hide them all up

In a certain case, it might happen that a third-party script or service that we are running on our application starts sneaking into the global context (or simply, the global object) of the application, or in the worst case, let’s say an attacker finds a vulnerability to inject malicious script in our application. In such scenarios, we open up everything in the global context for external or malicious scripts to spy on. Fortunately, closures come to the rescue, because even if a malicious script gets access to the global context of our application, it cannot access the variables hidden using closure. I think that’s amazing.

The following code segments are parts of one single code segment. I’ve broken them down for better understanding.

const seeds = {
    bondSeed: 7331,
    hulkSeed: 5647,
};

const generator = {
    generateBondValue: value => seeds.bondSeed * value,
    generateHulkValue: value => seeds.hulkSeed * value,
};

In the above code segment, the functions present in the generator object uses seeds object to generate values. The seeds object is declared globally (which is quite alerting). But, let’s check a better way to write this.

const betterGenerator = (function() {
    // Hidden using closure (inaccessible)
    const seeds = {
        bondSeed: 7331,
        hulkSeed: 5647,
    };

    return {
        generateBondValue: value => seeds.bondSeed * value,
        generateHulkValue: value => seeds.hulkSeed * value,
    };
})();

Here, the seeds object is declared as a variable of Immediately Invoked Function Expression (IIFE). The functions present in the object returned by IIFE use the seeds object from their outer function’s (IIFE’s) scope, demonstrating a typical use-case of closure. The best part is that there is no direct access to the seeds object unless we provide one more function in the returned object to modify the seeds object.

Let’s execute those functions.

console.log(generator.generateBondValue(2)); // 14662
console.log(generator.generateHulkValue(2)); // 11294

console.log(betterGenerator.generateBondValue(2)); // 14662
console.log(betterGenerator.generateHulkValue(2)); // 11294

Works perfectly! But, let’s say an unfortunate event happens, wherein a malicious code updates our global seeds object.

(function() {
    seeds.bondSeed = 0;
    seeds.hulkSeed = 0;
})();

Let’s execute them again,

console.log(generator.generateBondValue(2)); // 0
console.log(generator.generateHulkValue(2)); // 0

console.log(betterGenerator.generateBondValue(2)); // 14662
console.log(betterGenerator.generateHulkValue(2)); // 11294

And… that’s why the betterGenerator was better in design.

Interpret it once

We can also make use of closures in case of an event handler function which makes use of some dictionary object (or any kind of static data) to perform its operations. A regular function will keep interpreting that dictionary object every time the event is triggered, but if we manage to use closure here, the dictionary object will only get interpreted once.

Following is a regular function containing the dictionary object which is getting used in the alert function call.

const onClickHandler = textValue => {
    const dictionary = {
        ASAP: "As soon as possible",
        LOL: "Lauging out loud",
        BTW: "By the way",
        IMO: "In my opnion",
        TC: "Take care",
        GG: "Going good",
    };

    console.log("onClickHandler: Interpreted dictionary object");

    alert(dictionary[textValue] || "Error: Not found");
};

And, following is an IIFE having the same dictionary object. The function is returning another function that uses the dictionary object from its outer function’s (IIFE’s) scope. The same old trick.

const betterOnClickHandler = (function() {
    const dictionary = {
        ASAP: "As soon as possible",
        LOL: "Lauging out loud",
        BTW: "By the way",
        IMO: "In my opnion",
        TC: "Take care",
        GG: "Going good",
    };

    console.log("betterOnClickHandler: Interpreted dictionary object");

    return textValue => alert(dictionary[textValue] || "Error: Not found");
})();

Let’s use them.

using both the functions in UI

In the above UI, the button Check calls onClickHandler and Recheck button calls betterOnClickHandler. Both the buttons are responsible to pass the input value LOL to their respective functions. I clicked all of the buttons twice, let’s check the console.

console log

The betterOnClickHandler is an IIFE, and it runs only once when the page loads. The IIFE interprets the dictionary object only once and keeps it in memory to be used by the function it returns, which is the actual onClick handler. The other onClickHandler is a regular arrow function which interprets dictionary object every time it is called. I am completely unsure about the optimizations that are done by the JavaScript engine in the case of onClickHandler, but, from the bird’s-eye view, betterOnClickHandler looks like a good bet for me.

Have a nice day!


Kunal Mhatre

Hi, I am yet another Software Engineer and my interests revolve around UI, UX, and Product. I write about random stuff, I explore life and sometimes I look for stars in the skies.