Lexical scope and Closures

Lets us understand lexical environment and closures with a simple analogy.
Imagine you're in the city of Bengaluru. This city represents the global environment in JavaScript. Within this city, there are two apartment complexes β Prestige and Brigade β which represent two separate functions.
Each apartment has several houses, and these houses represent inner functions inside those parent functions.
Now, hereβs your task:
π§ You need to find a boy who lives in one of the houses in the Prestige apartment.
Step-by-step:
You start searching inside the house (inner function). If the boy is there, youβve found your answer!
If heβs not there, you look around in the Prestige apartment itself (outer function).
If heβs still not found, you search the city of Bengaluru (global environment).
But β β you cannot enter the Brigade apartment to look for this boy. Thatβs a separate, isolated environment. Even though it's in the same city, it's not connected to Prestige in any way.
What does this mean in JavaScript terms?
Each function has its own environment (like an apartment).
Inner functions (like houses) can access their own variables, variables in their parent function, and even global variables.
But they cannot access variables in sibling functions (like a house in Prestige trying to access a boy in Brigade β that's not allowed).
// Global Environment (City: Bengaluru)
const cityName = "Bengaluru";
function prestigeApartment() {
// Function Environment 1 (Apartment: Prestige)
const apartmentName = "Prestige";
function houseA() {
// Inner Function (House A inside Prestige)
const boyName = "Rahul";
console.log(`Boy is ${boyName} from house in ${apartmentName}, ${cityName}`);
}
return houseA; // Closure
}
function brigadeApartment() {
// Function Environment 2 (Apartment: Brigade)
const apartmentName = "Brigade";
function houseX() {
// Inner Function (House X inside Brigade)
// β Cannot access Prestige's variables
try {
console.log(`Trying to access boyName: ${boyName}`); // ReferenceError
} catch (e) {
console.log("Cannot access boy from Prestige inside Brigade.");
}
}
return houseX;
}
// π Task: Find boy from Prestige apartment
const searchBoy = prestigeApartment(); // Returns houseA function
searchBoy(); // β
Outputs boy info
// β Trying to search boy from Prestige inside Brigade
const searchWrong = brigadeApartment();
searchWrong(); // β ReferenceError or undefined
.
πΈ Lexical Environment
A Lexical Environment is the structure that holds variable/function declarations and the reference to its outer environment based on where a function is written (lexed) in the code.
π In simple terms:
Wherever a function is physically written in code, it determines what variables it can access β not where it is called from.
π‘ In Our Code:
function prestigeApartment() {
const apartmentName = "Prestige";
function houseA() {
const boyName = "Rahul";
console.log(`${boyName} from ${apartmentName}, ${cityName}`);
}
return houseA;
}
houseA()
is lexically enclosed withinprestigeApartment()
, so it can access:boyName
(its own scope)apartmentName
(parent scope)cityName
(global scope)
This chain of environments (house β apartment β city) is the Lexical Environment.
πΈ Closure
A Closure is formed when a function "remembers" and retains access to its lexical scope, even after the outer function has finished execution.
π In simple terms:
If a house in Prestige still remembers and can access its apartment and city details even after the apartment doors are closed β that's a closure.
π‘ In Our Code:
const searchBoy = prestigeApartment(); // returns houseA
searchBoy(); // still has access to apartmentName and cityName
Even though prestigeApartment()
has finished running, searchBoy
(which is houseA
) still remembers apartmentName
and cityName
.
That "memory" is what makes it a closure.
Subscribe to my newsletter
Read articles from Manjunath Nagendra directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
