Closures for Noobs
What is Closure and how it works in JavaScript and the Pros and Cons of using them.
Just like getting one at the end of a relationship goes a long way, while starting your relationship with JavaScript it's good if you get closure, better if in the beginning.
It’s a little tricky to get, hence is one of the most recurring topics during interviews and has a huge potential!
Without further ado, let's buckle up to be a JavaScript Noob!🤓
Closures
"Being able to reference a specific instance of a local binding in an enclosing scope is called Closure" - Eloquent JavaScript
I couldn't have put Closures any better than what Marijn explained in his book.
So to understand closures we need to dive deeper into some things from the quote
Enclosing/ Lexical Scope
Every function in JavaScript has its own lexical environment which has 2 main components
- Environment Record(variables, parameters)
Reference to the outer environment
Think of it like linked lists where every node(function) has its own data(environment record) and a reference pointing to the next node (parent's environment).
Whenever a function looks for a variable it first checks its own lexical environment(local scope) and if it's not present there then goes up to its parent's scope
And if it's not even there, it goes to its parent's parent function and the scope chain continues until the block ends
function outer() {
const x = 42;
function inner() {
console.log(x);
}
inner();
}
outer();
//Output:
// 42
When inner()
function is called it looks for x to log it, but as it is not in the local scope it will look for it in its parent's lexical environment
Functions in JavaScript
Functions are used to store specific code in their body,
but they also have a lexical environment in which they exist.
And every time the function is called, a snapshot 📸 of these local bindings is taken with the current state of the environment.
Different calls can't mess with one another's local bindings.
Think of it like this, let's consider yourself as the function and you have a slice of Pepperoni Pizza🍕(local bindings) with you. Every time the function is called a sibling of yours is created and is given a separate slice of Pizza, if the state of the environment is different at the time of call, the toppings(local bindings) of the slice will be different too.
And as the universal rules of siblings go, You can't mess with your sibling's slice. PERIOD. :')
And this specific functionality of JavaScript is known as CLOSURE
To see this functionality in action lets apply a debugger on the console.log()
in the above example, you can see in the Scope it contains a Closure which in turn contains the variable x
Awesomeness of Closures
I know, I know you are already thinking of thousands of ways you are going to play with them, let me tell you, You are already using them directly or indirectly in your code.
Remember the last time you used setTimeout or used Currying? all these cool functionalities use closures behind the curtain.
Let's make a cool multiplier whose code is ultra reusable:
function multiplier(factor) {
return (number) => number * factor;
}
twice = multiplier(2);
thrice = multiplier(3);
console.log(twice(10));
console.log(thrice(10));
// Output:
// 20
// 30
As you can see in the Scope, twice()
creates a closure with factor = 2
in its Lexical Scope and similarly thrice()
with factor = 3
.
Some common uses of Closures:
- Currying
- setTimeout
- Maintaining state in async functions
- Obviously the coolest multiplier in the world!
Darkside of Closures
Obviously, like everything in the world closures also have a Darkside.
Usually, after a function call, its state is garbage collected automatically,
But when closures come into the picture due to preserving its state every damn time the function is called, it takes a load on memory, though some browsers still intelligently garbage collect variables that are not being used.
Conclusion
JavaScript is one the best programming languages out there, If you understand how it works you can do wonders with it.
The ability to use Lexical scope inside a child function and that too with a separate instance for every call opens doors to many functionalities that can be implemented. Give it shot, try to play around with it, and still, if you are not able to wrap your head around it my DMs are always open, HMU.
See ya Noobs 👋 - A Noob