What is Closures in JavaScript
Before grasping closures, we must understand the environment they operate in: the Lexical Environment, which defines Lexical Scoping.
Lexical Environment
A Lexical Environment in JavaScript is a structure that stores all the variables and functions declared in the current scope, along with a reference to its parent scope (outer environment). Think of it as a map of variables that belong to a function or block — plus a link to where it was defined.
In simple terms, every piece of code in JavaScript runs inside some kind of environment that keeps track of what variables and functions are available to it.
It’s made up of two parts:
- Local Memory — where variables and functions declared in the current scope are stored.
- Reference to Parent Lexical Environment — so the current scope can access variables from its outer scopes.
When a function executes, JavaScript creates an execution context for it, which contains its lexical environment. This allows the engine to know where to find variables during execution.
When the JavaScript engine tries to access a variable, it first looks for the variable in the current lexical environment. If the variable is not found, the engine looks in the outer environment, and so on. This process is called scope chaining.
Example 1: Basic Lexical Environment
function outer() {
let outerVar = 'I am from outer function';
function inner() {
let innerVar = 'I am from inner function';
console.log(outerVar); // Accessible due to lexical environment
console.log(innerVar); // Accessible within the same scope
}
inner();
}
outer();Explanation:
- The inner() function can access both outerVar (from its parent scope) and innerVar (from its own local scope).
- This is because the inner function’s lexical environment has access to the outer function’s environment through scope chaining.
Example 2: Scope Chaining in Action
let globalVar = 'I am global';
function outer() {
let outerVar = 'I am outer';
function inner() {
console.log(globalVar); // From global scope
console.log(outerVar); // From outer scope
}
inner();
}
outer();
Result:
I am global
I am outerThis demonstrates how the JavaScript engine searches for variables:
- In the current scope.
- If not found, in the outer scope.
- Finally, in the global scope.
What are Closures in JavaScript?
A Closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
Get Umair Saeed’s stories in your inbox
Join Medium for free to get updates from this writer.
In other words, a closure gives a function access to its outer scope. Closure “remembers” the variables from its outer scope even after that scope has finished executing. A closure is created when a function is defined inside another function, and the inner function continues to have access to the outer function’s variables, even after the outer function has returned.
Example 1: Simple Closure
function outer() {
let count = 0; // outer variable
function inner() {
count++;
console.log(`Count: ${count}`);
}
return inner;
}
const counter = outer();
counter(); // Count: 1
counter(); // Count: 2
counter(); // Count: 3Explanation:
- The inner() function forms a closure with count from outer().
- Even though outer() has finished executing, the variable count is remembered because it’s referenced inside the inner function.
- This is the power of closures — preserving state across function calls.
Example 2: Multiple Closures with Independent States
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter1 = createCounter();
const counter2 = createCounter();
counter1(); // 1
counter1(); // 2
counter2(); // 1Each closure (counter1 and counter2) has its own separate lexical environment — they do not interfere with each other’s count value.
Example 3: Closure in Asynchronous Code
function delayedMessage(message, delay) {
setTimeout(function() {
console.log(message);
}, delay);
}
delayedMessage("Hello after 2 seconds", 2000);Here, the inner anonymous function passed to setTimeout forms a closure — it remembers the value of message even after the delayedMessage function has completed.
Conclusions
- A Lexical Environment stores variables and function definitions, along with a reference to its parent scope.
- Closures allow a function to access and remember its outer variables, even after the outer function has finished executing.
- Together, they define how scope and memory work in JavaScript, forming the foundation for many advanced concepts like callbacks, modules, and data privacy.








