Introduction to javascript Closures
When the inner function accesses values of the outer function it is known as closure. The closure preserves the outer scope inside its inner scope.
To understand the closures, you need to know how the lexical scoping works first.
Lexical Scoping
Lexical scoping defines the scope of a variable by the position of that variable declared in the source code. For example:
let myName = "Rishabh Thakur";
function myDetails() {
let myAge = 21;
console.log(`My name is ${myName} and my age is ${myAge}`);
}
myDetails();
In this example, myName
is a global variable. It is accessible from anywhere including within the myDetails()
function.
The variable myAge
is a local variable that is accessible only within the myDetails()
function.
if we try to access myAge
outside the myDetails()
function, you will get an error.
So the JavaScript engine uses the scope to manage the variable accessibility.
According to lexical scoping, the scopes can be nested and the inner function can access the variables declared in its outer scope. For example:
function outer() {
let myName = "Rishabh Thakur";
function inner() {
console.log(myName);
}
inner();
}
outer();
The outer function creates a local variable myName
and a function named inner()
.
The inner()
is the inner function that is available only within the body of the outer()
function.
The inner()
function can access the variables of the outer()
function such as myName
.
So, inside the outer()
function we call inner()
function to display the value of myName
.
Javascript Closure
Let's modify the outer()
function :
function outer() {
let myName = "Rishabh Thakur";
function inner() {
console.log(myName);
}
return inner;
}
let details = outer();
details();
Now, instead of executing the inner()
function inside outer()
function, the outer()
function returns the inner()
function object.
Outside of the outer()
function, we assigned details
variable the value returned by the outer()
function, which is a reference of the inner()
function.
Then we executed the inner()
function using the reference of that function: details()
. If you run the code, you will get the same effect as the one above.
However, the interesting point here is that, normally, a local variable only exists during the execution of the function.
It means that when the outer()
function has completed executing, the message variable is no longer accessible.
In this case, we execute the details()
function that references the inner()
function, the myName
variable still exists.
The magic of this is closure. In other words, the inner()
function is a closure.
A closure is a function that preserves the outer scope in its inner scope.
More Javascript Closure Example
The following example illustrates a more practical example of closure:
function greeting(message) {
return function(name){
return message + ' ' + name;
}
}
let sayHi = greeting('Hi');
let sayHello = greeting('Hello');
console.log(sayHi('Rishabh')); // Hi Rishabh
console.log(sayHello('Deepak')); // Hello Deepak
The greeting()
function takes one argument named message and returns a function that accepts a single argument called name.
The return function returns a greeting message that is the combination of the message and name variables.
The greeting(
) function behaves like a function factory. It creates sayHi()
and sayHello()
functions with the respective messages Hi and Hello.
The sayHi()
and sayHello()
are closures. They share the same function body but store different scopes.
In the sayHi()
closure, the message is Hi
, while in the sayHello()
closure the message is Hello
.
Summary
- Lexical scoping describes how the JavaScript engine uses the location of the variable in the code to determine where that variable is available.
- A closure is a combination of a function and its ability to remember variables in the outer scope.