So, What is Lexical Scope?
This is known as a Lexical scope. We can determine the scope of a component by the location of this component within the code.
Now, coming to the main question, what are closures and how does it work?
According to the definition given on MDN (Mozilla Developer Network) Web Docs,
“Closures are the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).”
However, this is not the simplest definition and hence, hard to understand by beginners so let’s break this down in simpler words:
A closures function gives access to an outer function’s scope from an inner function. It is the combination of a function and the surrounding state (lexical environment) within which that specific function was declared. Now, the lexical environment consists of all the local variables that were inside scope at the time the closures were made. We can create a closures function by defining a function inside another one. And then exposing it by returning or passing it to another function.
The function declared inside will have access to all the variables in the function from the outer scope, even after the outer function is done executing.
In the example of the closures above, we have defined a function multiply(a) that returns an anonymous function. The function it returns takes a single argument b and returns the multiplication of a and b. Let’s consider that multiply is a function factory that makes functions that can multiply a certain value to the argument passed. In the above example, the function factory creates two new functions – one that multiplies 10 to its argument, and one that multiplies 20.
When the code given in line no. 7 and line no. 8 gets executed multiple functions are called and stored in their respective variables. As you might be expecting that after the execution, arguments passed would no longer be accessible but it is not the case. Variables multiplyBy10 and multiplyBy20 hold a reference to the anonymous function which was returned when function multiply was called with arguments 10 and 20, respectively. The instance of returned anonymous function maintains a reference to its lexical environment, within which the passed arguments exist.
multiplyBy10 and multiplyBy20 are both closures. They have the same function definition but store different lexical environments and variable values. In multiplyBy10 the lexical environment of a is 10, while in the lexical environment for multiplyBy20, a is 20.
Running the Code
Let us run the above code in the console of a browser with the console.dir( ) method and see what information we get:
Now, here we can see that the console.dir( ) method is7 used to get information about the variables that hold the reference of the function, we can see that both are Closures with different lexical environments, i.e., 10 and 20.
In the above example, the outer function Counter returns the reference of the inner function increaseCounter(). Here, the function increaseCounter increases the outer variable counter to 1. The Counter( ) function updates its closures every time it is called. So calling the inner function multiple times will increase the counter by one every time. So, we can say that closures are valid in multiple levels of inner functions as well.
1. Emulating private methods
We generally use closures as access modifiers to give objects’ data a kind of private state. Data privacy is an essential property that helps us to program an interface, not an implementation. Any exposed method defined within the scope of the closure is privileged (accessed by only certain entities).
2. Maintaining states between function calls
Let’s suppose there is a function that multiplies different values together. One way of doing that is with the help of a global variable because they are available throughout the code. But, there is a drawback! Yes, a variable that is globally accessible can also be modified from anywhere in the code. We can achieve this using closures. Closures help in maintaining as well as capturing the state between different function calls without using a global variable.
3. Functional programming
Currying, which is an important function of functional programming, is also possible due to closures. It occurs when a function returns another function until we completely supply the arguments.
4. Create iterators
Apart from the above-mentioned, you can think of several other ways to use closures according to your needs. You just need to have a good knowledge of scopes and lexical scopes to get the best out of closures.
Question 1. Closures can be used for performing which of the following operations?
- Maintaining states between function calls
- Emulating private methods
- Creating iterators
- All of the above
Correct Answer: (d) All of the above
Correct Answer: (c) Lexical scoping
Question 3. Which of the following is mandatory to implement lexical scoping?
- Reference the current scope chain
- Dereference the current scope chain
- Return the value
- None of the above
Correct Answer: (c) 50
50 is not greater than 100, therefore if the condition fails then else condition will execute. Hence, 50 will be our output.