DEV Community

Cover image for Closure In JavaScript Loops and Modules.
Barnabas Babatunde
Barnabas Babatunde

Posted on

Closure In JavaScript Loops and Modules.

Hey, welcome back! Recently, I made a post titled: An Intro To Closure In JavaScript. You can check it here.

So, in this article, we are going to dive deeper. We will cover:

  1. Closure in Loops
  2. Closure in Modules

Let's dive in.

Closure In Loops

We will begin this section by examining two code snippets which look harmlessly similar, but give wildly different results:



Snippet one:

for(var i=0; i<10; i++){
    setTimeout(function timeCount(){
        console.log(i);
    }, 2000);
}
Enter fullscreen mode Exit fullscreen mode

Output:

10
10
10
10
10
10
10
10
10
10
Enter fullscreen mode Exit fullscreen mode



Snippet two:

for(let i=0; i<10; i++){
    setTimeout(function timeCount(){
        console.log(i);
    }, 2000);
}
Enter fullscreen mode Exit fullscreen mode

Output:

0
1
2
3
4
5
6
7
8
9
Enter fullscreen mode Exit fullscreen mode



Why do we get different results from both code snippets? Apparently it is because of the let and var difference. But do we actually know why this is so? Our purpose for using the for-loop was to actually access the incremented values of the variable i

We should be aware that using var i in the for-loop actually declares the variable in the enclosing scope(which is the global scope in our case). The for-loop block doesn't in itself create a scope. And variable i is in fact attached to the enclosing scope (global).

This explains the repeated 10 we obtained in the output of Snippet one - all ten timeCount functions declared during the course of the loop close over the same copy (same location in memory) of i. Since all ten functions execute after the loop ends, they all capture only the final value of i which is 10.

The case is quite different in Snippet two. By using a let i in the for-loop, the let keyword sort of hijacks the for-loop and turns it into a scope which can be closed over by the function timeCount.

One more thing, very interesting actually is that: when we use let in the head of a for-loop, the variable will be re-declared for each iteration of the for-loop. And its value for each iteration will be set to the value from the end of the previous iteration. Imagine it as a relay race team where different runners sprint through different sections of the track, with each runner continuing from where the last runner stopped.

Closure In Modules

JavaScript modules work on the principle of closure too. To illustrate, we will go through a very basic use case. Let's walk through the code snippet below:

function user(){
    //private data
    var username;
    var password;

    //public
    function setUsername(newUsername){
        username = newUsername;
        console.log("username created")
    }

    function setPassword(newPassword){
        password = newPassword;
        console.log("password created")
    }

    function showDetails(){
        console.log(`Username: ${username} Password: ${password}`);
    }

    //API
    return {
        setUsername,
        setPassword,
        showDetails
    };
}


var john = user();

john.setUsername("JohnDoe");
john.setPassword("john123");
john.showDetails();
Enter fullscreen mode Exit fullscreen mode

Output:

username created
password created
Username: JohnDoe   Password: john123
Enter fullscreen mode Exit fullscreen mode



First, we declare a function user. Next we create variables username and password which will hold private data. Next, we declare 3 functions setUsername to set the username variable to a value, setPassword to set the password variable to a value, and finally showDetails to print out the values of username and password.

We then create an object literal which holds all 3 functions as properties, and we return that object out of the enclosing function user.

Outside the declaration of function user, we create a module instance by executing user, and assigning the result to a variable john (the result being the object literal returned out of user). Through john(which now holds the object literal), we can access all 3 methods(property functions), as we did in the last three lines of code.

The 3 functions (returned out of user in an object literal) have closure over the private scope of the module instance(user()), and can therefore access (and modify) the private variables(or data) within that instance.

We can create as many module instances of user as we want. In each case, the returned-out functions(for each module instance) will have permanent access to the private variables in that module instance.

Now, modern module patterns can be much more sophisticated than this, but this illustration gives us an idea of how module design depends on the concept of closure.

Conclusion

In the last few minutes, we have seen how closure works with the for-loop and how using a let and a var in the head of a for-loop can give totally different results. We have also seen how modules depend on the concept of closure to actually work. In the next article on closure, we will see how closure is used to make data persistent.

Hope this was helpful. Till next time folks✌

Discussion (0)