In this blog, I will be explaining one of the important features of JS which is Closures
and why we need them. So let's dive in.
Closures?
Understanding Closure will help in understanding the other concepts in JS, like Higher-order functions and currying.
Generally, Higher-order functions do either of these two
- Allows the function to take the functions as an argument
- Allows the function to return the other functions.
The feature which we are about to see relates to returning the functions from the other function. What if, in addition to returning the function, we get information along with the function that is being returned?.
Let's take a look at an example,
Outer Scope and Inner Scope
You would have thought, like how the bar
was able to access outerScope
. It should not be possible, as the instance of the outerScope
created in the local memory will be erased once the execution of foo
is complete. There is also no reference to the variable present in the global scope.
But Javascript makes it possible. When the function foo
is called, both variable OuterScope
and the function bar
will be created inside the local memory that shares the same lexical environment. Due to which when bar
is returned from the foo
it will have access to the surrounding variables during the time of its declaration.
A closure
is the combination of the function and the lexical environment within which it has been created.
Technical Definition according to MDN
Technically, A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
In other words, closure gives you access to the scope of outer function from the inner function
How can we view the data returned with the inner function?
Generally, when a function is created, it will have hidden value [[scope]]
where it will contain all the information about the data that is being returned with the function.[[scope]]
is not accessible.
If we run the following in the chrome dev tools
console.dir(func)
We will get the following result in the console.
Now a real-world example on closure,
function trapA(a) {
return function (b){
return function (c) {
return a * b + c
}
}
}
console.log(trapA(2)(3)(4)) // 10
Same code with slight modification
function trapA(a) {
return function (b){
return function (c) {
return a * b + c
}
}
}
const wrapper = trapA(2);
console.dir(wrapper)
const trapB = wrapper(3);
console.dir(trapB)
const trapC = trapB(4);
console.log(trapC) // 10
Let us break it down.
Once the execution of
trapA
is complete, it returns the function definition of the anonymous function and the value ofa
. It is stored inwrapper
.console.dir
ofwrapper
will give the closure details.Upon the execution of the first anonymous function stored in
wrapper
, the value ofa
,b
, andanonymous function
are returned and stored intrapB
.console.dir
oftrapB
will give the closure details.Finally, the second anonymous function is executed and the expression is evaluated successfully, as it will have access to
a
,b
, andc
.When the final
console.log
statement is executed, the value10
is returned to the screen.
Below is the screenshot for the above code snippet that depicts the value stored in [[scope]]
for every function call.
Why closures
With Closures, we can emulate the concept of the private method in Javascript, as they are not available natively. Let's see an example of how we can achieve that via closure
Based on the above code snippet, three functions fullName, addNum, and getNum
share the same lexical environment, and thanks to Javascript's closure concept it will access the variable num
and it won't be accessible outside of the function.
That's a wrap on Closures. Thank you for your time and I hope everyone understood the concept. Any suggestions and critics are most welcome.
Top comments (0)