I hope everyone in the room is excited to learn about it! Let's go on a closure's roller-coaster ride then!
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
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.
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?
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
Module design pattern
Currying in Javascript
Memoize
Maintaining state in the async world
Data Hiding and encapsulation
Iterators
setTimeouts
DISADVANTAGES OF CLOSURE'S
Variables used by the closure will
not be garbage collected
If closures are not handled properly it will cause a problem of
memory leak
HOW CLOSURE AND GARBAGE COLLECTOR ARE RELATED?
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
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! ๐
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!
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!