Closures: A breakdown - Part 1
Tags: javascript, vscode
Published: 2021-01-08 15:01:41

Closures are one of the most intriguing concepts in Javascript. I've been referring to a ton of resources for clarification. For me what worked was [EJS](https://eloquentjavascript.net/) and [Namasthe Javascript](https://youtube.com/playlist?list=PLlasXeu85E9cQ32gLCvAvr9vNaUccPVNP). When I combined these two everything fell into place. Let's dive into dissecting closures. I'll be using the same example as in Namasthe JS with some refactoring for better understanding.

Here's the code that we are going to mess around with.
```
function outer() {

    for(var i=1; i<=5; i++) {
            setTimeout(() => {
                console.log(i)
            }, i*1000)
    }
    console.log("I run first");
}

outer();
```
Take a moment to think about the output, get your neurons to start firing and then run the code in your fav IDE. Spoiler Alert! The output is going to be 'I run first' and then '6' logged 5 times in the console at the end of 5 seconds. '6' is logged each second as soon as you run the code. But, why '6'? why isn't it logging '1', '2', '3', '4', '5' after each second? The culprit is the `var` keyword in `for` loop. 
The concepts at play here are scope of `var`, function call, async programming, closures and references. We'll go through it one by one. Firstly, it is the async behaviour of `setTimeout`, which is why 'I run first' gets logged in before '6'.

For a moment imagine, there's no `outer()` function, there's only a `for` loop. Here `i` will be added to window object and its value will change as the loop runs. `setTimeout` is run 5 times asynchronously and the callback function exist in parallel but with different timers. `i*1000` gets resolved when for loop runs, but `console.log(i)` is still dormant. So, when the timer runs out the value of `i` has been changed and all these 5 copies of callback functions points to the same `i` which exists in the window object. And that `i` is '6' now.

Now let the `outer()` function exist and we call it. In the current situation 'var' scope is limited to `outer()`, since its function scoped. We run the program, `outer()` is called, `for` loop is run, same thing happens as above but `i` is not added to window object rather its in the local scope of `outer()`. So now when the timer runs out for the first `setTimeout` of 1 second, `callback` function wakes up from its sleep and finds `i` in closure formed with `outer()` function.

![image1](https://dev-to-uploads.s3.amazonaws.com/i/pe88aga9nw37bg4wprfx.png)

Closure is basically a function and its environment that's created each time a function is called. This environment has reference to the instance of bindings of its parent and above when the function was created. This feature helps functions to get access to bindings in its outer scope. To put it in different terms, a child function knows the assets(bindings/variables) owned by its parent, grandparent and so on. Whenever a child is called, it recalls its roots if need be.

Now `i` is up for grabs with the closure formed with `outer()`. Remember `outer()` is called just *once* and therefore there's only one instance of this environment. Even in this environment `i` is changed by `for` loop. So all the copies of `callback` function points to `i` which is already '6'. All because of the powerful scope of `var`.

Our goal is to get the output as '1', '2', '3', '4', '5'. For that we need a new instance of `i` for every step of the `for` loop. In 2015, a new keyword `let` was introduced in JS which is block scoped. Since the block is run every time the loop condition is met, a new instance of `i` is created for every block with references to different values. Here one should note that, there are 5 blocks existing simultaneously, with different values of `i`. So when the timer runs out, the callback remembers its block environment which has a particular value of `i`, kind of a closure but there is no parent function involved. Hence we'll get the desired output.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0vz0v349p67sokvxqu07.png)

What if we don't want to use `let` but want to continue with `var`. Here the idea is to hijack value of `i` and call a function each time the loop is run, so that we have a new closure environment with each value of `i`.
```
function outer() {

    for(var i=1; i<=5; i++) {
        function inner(a) {
            setTimeout(() => {
                console.log(a)
            }, a*1000)
        }
        inner(i);
    }
    console.log("I run first");
}

outer();
```
As per the above code, the value of `i` is taken over by `a` each time the loop runs. Since the function `inner()` is called 5 times, there are 5 closures with `inner()` existing in parallel which have different values of `i` captured by `a`.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9qkam7vw2lftxa6z8zsf.png)

Now 5 timers have started ticking at almost the same time. First, the timer for 1 second ends, `callback` function wakes up from its dormant state to find `a`. But where is `a`? `a` is in the closure formed with `inner()` function where `a` was set to '1'. To put it in GOT words, the callback function remembers. It knows `a` was 1, when the timer was set to 1 second . Remember there's 5 different copies of the callback function and 5 closure instances of `a` with values '1', '2', '3', '4', '5'. Each copy gets called when its timer runs out. 

I would suggest you to use the debugger in your browser to thoroughly understand the workings of this. I have attached some screenshots for reference for each method i.e `var`, `let` and `var` with a inner function. In the end it's all magic by JS.

Comments/Corrections are welcome.