DEV Community

Cover image for Closures in JavaScript.
NikhilBelide
NikhilBelide

Posted on • Updated on <time datetime="2021-08-30T15:04:12Z" class="date-no-year">Aug 30</time>

Closures in JavaScript.

What is a Closure?

A Closure is bundle of a function along with its lexical environment.

In simpler terms, when a function is run, it checks in its surrounding state (lexical environment) and holds on to any variables even after the block in which those variables are has finished executing, if it thinks that it is going to need them in the future.

Here, function holds on to the reference to that variable and not the actual value itself and includes the parent scopes as well.

So, A continuous scope which holds the variables even after it has exited a block after execution so that they can referenced in future is a CLOSURE.

This scope along with is private variables exist as long as the function continues to exist.

Every JavaScript developer has come across closure even though they did not know this concept existed.

Let us go solve a few examples which explain this concept in a better way.

Let us start with a simple one.

let outer= function(){
    let a=5,b=20
    function insideOuter(){
        return a+b
    }
    return insideOuter
}



let outputOne=outer()
console.log(outputOne)
console.log(outputOne())



--output on console is ---
ƒ insideOuter(){
        return a+b
    }
25.
Enter fullscreen mode Exit fullscreen mode

If you see above we are calling a function which returns another function called insideOuter.

We pass this into a variable called outputOne so that we can call that whenever needed.

When outputOne is called the insideOuter function is called which is dependent on the outer function scope because a when it is called, it sees the environment in which it was created and not the environment in which it was called.

So, a closure is which is already formed with that block.

But how do we know if it has formed or not? We cant see it right? Actually we can.

Let us put the execution on hold by placing a debugger at line 10 or at line 4 and lets observe the console.

Alt Text

If you observe carefully, at the bottom right it shows that it has formed a closure with outer function scope.

Now, As I said this scope will also include the parent scope as well if needed. So, let us add a few more steps to the code.


let outer= function(){
    let a=5,b=20
    function insideOuter(){
        let c=7.5
        function innerMost(){
            return (a+b+c)
        }
        return innerMost        
    }
    return insideOuter
}




let outputOne=outer()
console.log(outputOne)

let outputTwo=outputOne()
console.log(outputTwo)

let result=outputTwo()
console.log(result)

Enter fullscreen mode Exit fullscreen mode

Here, we have outer which returns insideOuter function.
As we know this forms closure. When the return function is called that returns another function innerMost.

This innerMost first forms closure with insideOuter scope. But that scope does not have all the variables needed for it to run independently right. So, it looks above another level and when found it forms a closure.

Alt Text

In the above image, we can clearly see that since the innerMost is forming closure with both insideOuter and outer function environment/scope.

So, even after 1000 lines of code when we execute outputTwo as a function, the scope still persists.

Here is such an example.

c3

Let us look at another example.


let multiplier =factor=>{
    return number=>{
        return number*factor
    }
}


let thrice=multiplier(3)
let thriceOfFive=thrice(5)
console.log(thriceOfFive)


---output on console ---
15

Enter fullscreen mode Exit fullscreen mode

Here, Anonymous function forms closure with multiplier function environment and holds onto the variable factor.

Alt Text

Let us look at another example.
This is one of the most asked questions in interviews on Closure.
setTimeout function can mess the way closures are formed. Actually it will make us confusing.



for(var i=0;i<3;i++){
    function one(){
        console.log(`${i} from function one`)
    }
    const two=()=>{
        console.log(`${i} from function two`)
    }
    setTimeout(two,1000)
    one()
}


Enter fullscreen mode Exit fullscreen mode

Here, We created a for loop and for every iteration we are calling the functions defined inside and logging the output.

The job of the functions is simple. They need to log a statement with i variable value at that particular point of time.

Take a good look at the code and guess the output.

You might think that the output might be this. I thought the same as well


0 from function two
0 from function one
1 from function two
1 from function one
2 from function two
2 from function one

Enter fullscreen mode Exit fullscreen mode

Or something else, but the actual answer is this.

c5

But why? What exactly happened? Why did we even get the output like this?

This is because of two reasons.

First one is that JavaScript does not wait for the time declared on setTimeout it instead takes timer along with the data that needs to be processed and stores it somewhere and continues with the rest of the program and once the timer expires it processes that part of the data.

And this is what causes the main problem. By the time the timer expires, since JavaScript does not wait, it has already run through the loop and as a result i value gets updated while function two is relaxing somewhere else function one gets executed.

Second reason is that, since we declared variable ** i** using var keyword and that is only function scoped not block scoped. So i here is on the global space. So, it does not need to form any closure as it will always be available.

So, since i is global, function two will point to the same reference and when the timer expires the i value at that particular point of time is logged.

Then how to we get an output where function two holds i? Simple. Lets make sure closure is formed. We can do this by making the variable i be declared using let keyword.



for(let i=0;i<3;i++){
    function one(){
        console.log(`${i} from function one`)
    }
    const two=()=>{
        console.log(`${i} from function two`)
    }
    setTimeout(two,1000)
    one()
}


Enter fullscreen mode Exit fullscreen mode

Since let is block scoped, functions will form a closure with that block. So, now we get the output as follows.

c6

If you look below, when the variable i was declared using var it is on global space.

c7

While, when the variable i was declared using let both functions are forming closure with it. Which means i when formed, it points to a new reference for each and every function call.

c8

This is what closures are.

c0

Think of closure as saving a post on Instagram so that you can reference it later and once you decide its no longer need it you just remove that. The difference is that JavaScript does this job for us.

Thanks for the read.
Any feedback is highly appreciated.

Happy coding. 🤎

Discussion (0)