Understanding The Scope (Backbone Closures)
The JavaScript uses the lexical scoping of variables. Simply the placement of the variable will determine who can access it. The access to the variable does not depend on how and when the code runs. Javascript determines the access of variables at compile time itself.
Read More, Check out the interactive demo here
Hierarchy of Scope In Javascript
Global Scope
This are the variables which are accessible by all functions. We define them at the outermost place in our code structure.Function Scope
These are the variables which we define inside the function (Withvar
keyword). They are only accessible inside the function and children functions in which we define the variable.Block Scope
The ES6 module provides us the block scope variable. These are the variables which we define inside any pair of curly braces{ }
. (using keywordslet
andconst
).
Understanding The Closures (Function's Backpack)
function exFunctionA() {
const outerVariable = "I'm from the outside!";
function exFunctionB() {
console.log(outerVariable); // Accesses the variable from its "backpack"
}
return exFunctionB;
}
const myClosure = exFunctionA(); // outerFunction runs and is gone...
myClosure(); //...but innerFunction still has its backpack! Logs "I'm from the outside!"
Read More, Check out the interactive demo here
The best analogy to understand closures is Backpack.
- Think when we define any function (Function A), we define some variables inside it (lexical scope). Here we define the variable
outerVariable
inside Function A. - Think, to remember this information, functions create a backpack and hold all these values inside it.
- Then again we define another function (Function B) inside our parent function (Function A). The Function B has access to the variable defined in the parent function (Function A).
- So now our inner function will create a backpack and hold all this information.
When our outer function (Function A) executes and returns its context and lexical scope also finishes. But remember our inner function (Function B) has its own backpack, and inside the backpack it has the variable from the parent Function A (which is already executed).
Now this phenomena, after the execution of parent Function A and lapsing of its lexical scope. Our inner Function B can still access the variable which was defined inside the parent Function A is called Closures.
A closure = (function + its lexical environment)
Practical Uses of Closures
Read More, Check out the interactive demo here
1. Encapsulated counters
For example, we create a function createCounter()
. We declare variable count
inside it. We also declare another function increment()
which uses the count
variable. createCounter()
function returns increment()
function.
Now the createCounter()
returns us the increment
function. The increment
function has access to the count
variable. We can use the increment()
function and change the value of the count
variable. This allows use to encapsulate variables and avoid polluting our code.
2. Private variables & Module pattern
As per our earlier conversation in the above example. We can create a private variable inside a function. And returns an inner function which has access to variable. This hides the variable from direct access. This allows use to create private API without exposing state of private variable.
3. Event handlers / Callbacks
Closure helps us to preserve the context of asynchronous code. If we attach a callback with a variable from an outer scope, the closure preservers the variable. The callback can access the variable from the outer scope, even the parent function returned way back.
4. Iterators / Generators
We can create iterators or generators (inner functions) which can remember their progress using closure.
Conclusion
In simple words, closures are the function with awareness of their lexical scope.
We can leverage this utility for many use cases, some of the use cases we discussed.
If you know how to use closures more effectively, please comment down.
Top comments (0)