Understanding JavaScript Closures
Understanding JavaScript Closures - lexical environment, scope chain, and practical examples
A closure is the combination of a function and the lexical environment within which that function was declared. In JavaScript, every running function, code blocks {…}, and the entire script have an internal (hidden) associated object called the Lexical Environment.
Lexical Environment
A lexical environment consists of two parts:
- Environment Record: An object that stores all local variables as its properties (and some other information like the value of
this). - A reference to the outer lexical environment
Variable Declarations
When the program starts executing, let variables are first declared in an uninitialized state until they are actually declared and can be used.
// code -> lexical environment -> outer lexical environment
// execution start -> foo: <uninitialized> -> null
let foo = 1; //-> foo: 1
foo = 2; //-> foo: 2
Function Declarations
When the program starts executing, functions are initialized first.
// code -> lexical environment -> outer lexical environment
// execution start -> foo1: <uninitialized> -> null
// foo2: function
let foo1; //-> foo1: undefined
foo1 = 2; //-> foo1: 2
function foo2() {
let v = 1;
}
Let’s take a closer look at foo2:
// code -> lexical environment -> outer lexical environment
function foo2() { //-> v: <uninitialized> -> {foo1: 2, foo2: function} -> null
let v = 1; //-> v: 1
}
When accessing a variable, the search starts from the inner lexical environment, then the outer environment, then even more outer environments, and so on, until reaching the global lexical environment.
Closure Example
function foo1(x) {
return function foo2(y) {
return x + y;
};
}
var add5 = foo1(5);
var add10 = foo1(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
In this example:
foo1creates and returns an inner functionfoo2- The inner function
foo2has access to the parameterxfrom its outer functionfoo1 - Even after
foo1has finished executing, the returned function still remembers the value ofx - This is a closure: the combination of the function
foo2and the lexical environment in which it was created
Key Characteristics of Closures
- Data Encapsulation: Closures allow you to create private variables
- State Persistence: The outer function’s variables remain accessible even after the outer function returns
- Factory Functions: You can create multiple instances with different private states
Practical Applications
Closures are commonly used for:
- Module patterns
- Event handlers
- Callback functions
- Function factories
- Data privacy and encapsulation
Understanding closures is essential for mastering JavaScript’s scope and functional programming patterns.