A closure is the combination of a function bundled together with references to its surrounding state. It’s a simple and useful technique once you understand it.
Closures are one of the most widely discussed and still confusing concepts in JavaScript—and also one of the most common questions you are likely to encounter in an interview when applying for a JavaScript position. As the title says, I will be making the topic clearer and easier to understand.
A closure is a feature in JavaScript where an inner function has access to the scope (variables and parameters) of its outer functions, even after the outer function has returned.
Note: Scope in JavaScript refers to the current context of code, which determines the accessibility of variables to JavaScript. The two types of scope are local and global:
In other words, a closure gives you access to the following scope:
Here’s is a simple example of a closure in JavaScript:
// Defining the outer function.
function enclosing() {
var x = "outer";
// Defining the inner function.
function inner() {
var y = "inner";
console.log(x, y)
}
return inner;
}
// invoking enclosing returns the inner function.
var a = enclosing()
a()
We defined two functions:
enclosing
with a variable x
that returns a nested functioninner
with a variable y
that logs both the value of its variable and that of its parent functionNote: A function can return another function in JavaScript. A function that is assigned to a variable is called function expression. And, the
return
statement does not execute the inner function—a function is executed only when followed by()
—but rather thereturn
statement returns the entire body of the function.
This is a step-by-step walkthrough of the flow of execution:
enclosing()
at line 13, variable x is declared and assigned a value.inner
.return inner
returns the entire body of the function inner
.a
. Thus, a
will store the following: function inner() {
var y = "inner";
console.log(x, y)
}
outer()
finishes execution, and all variables within the scope of outer()
now no longer exist.Note: The lifespan of a variable defined inside a function is the lifespan of the function execution.
What this means is that in console.log(x, y)
, the variable x
exists only during the execution of the enclosing()
function. Once the enclosing
function has finished execution, the variable x
no longer exists.
Now, we know that the function enclosing
returns a function, and that gets stored in variable a
.
a
is a function, we execute it on line 14. When we execute a()
, we are essentially executing the inner
function. Let us examine step-by-step what happens when a()
is executed:y
is created and assigned a value.x
and its local variable y
.Now, you may be asking, “How does the function inner
have access to its parent function variable x
, since its parent function has finished execution long before we invoked a()
and we noted earlier that the lifespan of a variable defined inside a function is the lifespan of the function execution?”
The answer to this question is …
The function inner
has access to the variables of the enclosing function due to closures in JavaScript. In other words, the function inner
preserves the scope chain of function enclosing
at the time it was executed, and thus can access the parent’s function variables.
The function inner
had preserved the value of its parent function variable x
when the parent function was executed and continued to preserve (closure) it.
It now refers to its scope chain and notices that it does have the value of variable x
within its scope chain since it had enclosed the value of x
within a closure at the point when the enclosing()
function had executed.
Thus, that is how JavaScript can remember not only the value but also the variable of the parent function after it has long finished execution.
Closures are useful in hiding implementation details in JavaScript. In other words, it can be useful to create private variables or functions.
The following example shows how to create private functions and variables.
var name = (function() {
var username = "";
function setName(val) {
username = val;
return username
}
return {
set: function(val) {
return setName(val);
}
};
})();
console.log(name.set("John Doe"))
In the above example, set
becomes a public function because it is included in the return object, whereas function setName
becomes a private function because it is not returned and can only be used internally within the parent function.
Hopefully these step-by-step explanations helped you understand the concept of closures in JavaScript.
Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.