Search Knowledge

© 2026 LIBREUNI PROJECT

Modern JavaScript & Ecosystem / Functional Foundations

Closures and Lexical Scope

Understanding Scope

In computer science, scope refers to the region of a program where a binding (a variable or function name) is valid. JavaScript utilizes lexical scoping, also known as static scoping. This means that the scope of a variable is determined by its position within the source code during the parsing phase, rather than how the code is called at runtime.

The Execution Context and Variable Environment

When the JavaScript engine executes code, it creates an Execution Context. Every context has a Lexical Environment, which consists of:

  1. Environment Record: A map of variable names to their values.
  2. Outer Environment Reference: A link to the parent lexical environment.

This linkage of environments forms the Scope Chain. When a variable is accessed, the engine searches the current environment record. If not found, it moves up the reference to the parent environment, repeating this until it reaches the global scope.

The Nature of Closures

A closure is the combination of a function bundled together with references to its surrounding state (the lexical environment). In JavaScript, closures are created every time a function is created, at function creation time.

Essentially, a closure gives a function access to its outer scope even after the outer function has finished executing. This is possible because the inner function maintains a reference to the outer environment record, preventing it from being garbage collected.

javascript
1function createCounter() {
2 let count = 0; // Encapsulated variable
3 
4 return function() {
5 count++;
6 return count;
7 };
8}
9 
10const counter = createCounter();
11console.log(counter()); // 1
12console.log(counter()); // 2

In the example above, createCounter returns an anonymous function. Even though createCounter has finished its execution, the returned function “remembers” the environment where count was defined.

Applications of Closures

Private State and Encapsulation

Before the introduction of private class fields (#field), closures were the primary mechanism for implementing privacy in JavaScript. By defining variables within a function scope and returning an object with methods that access those variables, you can create “private” data that cannot be manipulated from the outside.

Function Factories

Closures allow for the creation of functions that are pre-configured with certain parameters.

javascript
1function makeAdder(x) {
2 return function(y) {
3 return x + y;
4 };
5}
6 
7const add5 = makeAdder(5);
8const add10 = makeAdder(10);
9 
10console.log(add5(2)); // 7
11console.log(add10(2)); // 12

Common Pitfalls: The Loop Problem

A classic issue involving closures occurs when using var inside a loop with asynchronous callbacks. Because var is function-scoped (or global if outside a function), all callbacks share the same variable instance.

Fixing the Loop Closure

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log("Index:", );
  }, 100);
}

Memory Considerations

While closures are powerful, they must be used judiciously. Since a closure maintains a reference to its outer scope, variables within that scope cannot be garbage collected as long as the closure exists. If you create many closures that maintain references to large objects (like DOM nodes or large arrays) that are no longer needed, it can lead to memory leaks.