The Mechanics of Closure

A Closure is formed when an inner function returned from outer function is accessing and modifying the variable defined in outer function. Even after outer function is popped off Call Stack the inner function is able to access and modify the variable defined in outer function because of Heap Promotion.

A. The Stack Problem

Normally, when a function finishes executing, its Stack Frame is Popped. All local variables should disappear.

function outer() {
  let count = 0;
  function inner() {
    count++;
  } // inner uses count
  return inner;
}
 
const myFunc = outer(); // outer() runs and POPS.
// count should be gone.
myFunc(); // But this works. How?

B. The Heap Solution

  1. The Scan: During the Creation Phase of outer function Execution Context, the engine sees that inner function refers to variable in outer function.
  2. The Promotion: The engine realizes variable accessed in inner function cannot live in the temporary Stack Frame. It allocates a specific Context Closure Heap Object and stores referenced variable there.
  3. The Link: The returned inner function has its [[Environment]] pointer linked to this Heap Object, not the dead Stack Frame.
  4. Result: inner function carries the function logic plus a reference to the Heap data it needs.

C. Practical Applications: Functional Patterns

Since Closures allow functions to remember arguments provided in the past (by storing them in the Heap), we can leverage two powerful functional programming patterns.

1. Currying

Currying is a function transformation where a function that takes multiple arguments is converted into a sequence of functions that each take a single argument. f(a, b, c) -> f(a)(b)(c)

The Mechanism: We manually nest functions so each level handles exactly one argument.

// A manually 'curried' function structure
function multiply(a) {
  return function (b) {
    return a * b; // 'a' is remembered from the Closure
  };
}
 
// Currying allows us to call the chain:
console.log(multiply(2)(5)); // 10

2. Partial Application

Partial Application is the process of fixing a specific number of arguments to a function, producing a new function of fewer arguments.

While we can use Currying to achieve this, Partial Application is distinct because it doesn't strictly require the f(a)(b) structure. We can use methods like .bind() on standard functions.

// A standard (non-curried) function
function add(a, b) {
  return a + b;
}
 
// We use .bind() to partially apply '5' to the first argument 'a'
// '5' is stored in the closure created by bind
const addFive = add.bind(null, 5);
 
console.log(addFive(10)); // 15

The IIFE (Immediate Invocation)

It is a function expression that is defined and run immediately.

(function () {
  // Logic here
})();

An IIFE creates a temporary Function Scope.

  • Use Case: Callback Function, For Creating Variable in same scope.

Summary Table

FeatureBehaviorMemory Location
Standard FunctionRuns and EndsVariables on Stack (Popped)
ClosureRemembers ScopeVariables Promoted to Heap
IIFERuns OnceTemporary Stack Frame
ConceptThe Why
Heap PromotionTo ensure variables survive after the Stack Frame dies.
IIFETo avoid polluting the Global Scope with temporary variables.