返回文章列表
javascript

Understanding JavaScript Closures

Understanding JavaScript Closures - lexical environment, scope chain, and practical examples

Aaron

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:

  1. Environment Record: An object that stores all local variables as its properties (and some other information like the value of this).
  2. 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:

  • foo1 creates and returns an inner function foo2
  • The inner function foo2 has access to the parameter x from its outer function foo1
  • Even after foo1 has finished executing, the returned function still remembers the value of x
  • This is a closure: the combination of the function foo2 and the lexical environment in which it was created

Key Characteristics of Closures

  1. Data Encapsulation: Closures allow you to create private variables
  2. State Persistence: The outer function’s variables remain accessible even after the outer function returns
  3. 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.