Do you know Closures?

Do you know Closures?

May be Yes or May be No ?

I hope everyone in the room is excited to learn about it! yes Let's go on a closure's roller-coaster ride then! ride-together

What is CLOSURE?

CLOSURE = FUNCTION + LEXICAL ENVIRONMENT
Now, LEXICAL ENVIRONMENT means references to its surrounding state!
For example,

function outer() {
    var a = 7
    function inner() {
        console.log(a, "I am inside inner")  
       // here, a variable can accessed... through lexical environment
    }
    inner()
}

outer()

Explanation of Lexical Environment: Here, inner() function has access to variable a which is defined in its parent function i.e outer(). This is what lexical scoping is!

And above example forms a closure too! Let me explain how...

Now,

var b = 9
function outer() {
    var a = 7
    function inner() {
        console.log(a, b, "I am inside inner")
    }
    return inner   
   //so here function is not returned whereas whole closure is returned
}

const output = outer()  
console.dir(outer)

Note: Both snippets of code is the same!

Explanation: Here, the return inner forms a closure and therefore we are able to access the value of variable a! Whereas variable b is accessed via Global scope

output-1.png

A Closure is a combination of function bundled together with its surrounding references(Lexical environment). In simple terms, it means, closure gives you access to an outer function’s scope from an inner function.

wow

GOTCHAS AROUND CLOSURE'S

  • Re-assign the variable

For example,

function outer() {
    var a = 7
    return function inner() {
        console.log(a)
    }
    a = 10
}
var output = outer()()

Here variable a is reassigned with a new value i.e 10.
So, what you think will be its output? deep-think

Ohh yes, we will get the value of the a variable as 10 and not 7 because remember I told you that we look for reference! 😅

  • Nesting at any level is possible

For example,

function outermost() {
    var a = 10
    function outer() {
        var b = 7
        function inner() {
            console.log(a, b)
        }
        return inner
    }
    return outer
}
const output = outermost()()()  //currying

So, inner forms closure with its parent outer() as well as its grandparent outermost()

ADVANTAGES OF CLOSURE'S

  1. Module design pattern

  2. Currying in Javascript

  3. Memoize

  4. Maintaining state in the async world

  5. Data Hiding and encapsulation

  6. Iterators

  7. setTimeouts

DISADVANTAGES OF CLOSURE'S

  1. Variables used by the closure will not be garbage collected

  2. If closures are not handled properly it will cause a problem of memory leak

So if some variables defined in scope are not used in Closure then the browser smartly collects them in Garbage Collector

For example,

var b = 9
function outer() {
    var a = 7
    var c = 5
    function inner() {
        console.log(a, b, "I am inside inner")
    }
    return inner   //so here function is not returned whereas whole closure is returned
}

Here, once the function outer is invoked, variable c is smartly collected into the garbage because then closure doesn't require the c variable

CLOSURE + SETTIMEOUT

trick

function outer() {
    var i = 1  //scope of i is outer 
    setTimeout(function () {
        console.log(i)  //accessed here 
    }, 1000)
}
outer()

So the function of setTimeout forms a closure and remember the reference of variable i!

function outer() {
    for (var i = 1; i <= 5; i++) {
        setTimeout(() => console.log(i), i * 1000)
    }
}
outer()

Here, I want you to think about the output! 😁 think

Yes, So it prints 6 five times in console!! 😅 and not 1,2,3,4,5

Explanation: Because loop goes into call stack and executes while setTimeout goes into browser API and attaches the timer with it. Until the call stack frees up and execute callbacks of setTimeout variable a becomes 6 and I told you that it remembers the variable reference and not value. Hence we got 6

How to solve this problem then?

function outer() {
    for (let i = 1; i <= 5; i++) {
        setTimeout(() => console.log(i), i * 1000)
    }
}
outer()

Use let because it has a block scope and it will refer to that!

Congratulations!

We are done, I hope you learnt something new and enjoyed the blog!

thank

PS: I have understood all these concepts from the Namaste Javascript playlist on Youtube! So thank you, Akshay Saini!

In case of any mistakes in the blog, please tell me in the comments, I would love to correct those!