The Backpack And Persistent Scope

Closure is the 'backpack' of data that a function carries around with it, no matter where it goes. It's the persistent memory that sticks around between invocations.

April 25, 20264 min read2 / 3

Normally, when a function finishes executing, its local memory is deleted. But what if our functions could hold onto live data between executions? What if they could have a persistent memory that sits alongside their definition? This is the essence of Closure.

The Essentials

  1. Lexical Scoping: The rule that where you define your functions determines what data it has access to when you call it.
  2. The Backpack (PLSRD): A hidden store of data (Persistent Lexical Scope Referenced Data) that is attached to a function when it is born.
  3. Independent Contexts: Every call to the outer function creates a brand new, independent backpack for the returned function.

The Hypothesis: Where do we look?

To understand closure, we first have to answer a question. When a function references a variable that isn't in its local memory, where does it look next? This builds on our understanding of how functions are returned and stored.

JavaScript
function outer() { let counter = 0; function add1() { counter++; } return add1; } const myNewFunc = outer(); myNewFunc(); myNewFunc();

When we run myNewFunc(), it hits counter++. It checks local memory (not there). Where does it look next?

  • Hypothesis A (Call Stack): Does it go to where it was called (the global context)?
  • Hypothesis B (Definition): Does it go to where it was defined (inside outer)?

If it's the Call Stack, it should fail because counter isn't global. But it doesn't fail. It finds counter because JavaScript follows Lexical Scoping (also called Static Scoping).

The Backpack (PLSRD / COVE)

The moment add1 is defined inside outer, it gets a hidden bond to its surrounding data. It doesn't just save the function definition; it pulls a "backpack" of all the live data from that execution context.

Technical names for this backpack include:

  • [[scope]]: The hidden property where the link is stored.
  • COVE: Closed Over Variable Environment.
  • PLSRD: Persistent Lexical Scope Referenced Data.
  • Closure: The colloquial name for this hidden store.
JavaScript Execution Engine
Thread of Execution
1function outer() {
2 let counter = 0;
3 function add1() { counter++; }
4 return add1;
5}
6const myNewFunc = outer();
7myNewFunc();
8myNewFunc();

Step 1:We run outer. Inside, counter is 0 and add1 is defined with a hidden bond to its surrounding memory.

Memory
outerf
Call Stack
Global
Bottom of Stack

Multiple Backpacks are Independent

Crucially, every time you call outer, you get a fresh execution context and a fresh counter = 0. If you save the result of a second call to a new label anotherFunc, it gets its own, completely separate backpack.

JavaScript
const anotherFunc = outer(); // A brand new call, a brand new backpack anotherFunc(); // its counter becomes 1 myNewFunc(); // its counter is still 2 (from previous calls)

This precision is vital. anotherFunc has nothing to do with myNewFunc, and neither of them has an ongoing relationship with outer. They simply hold onto the data they "dragged out" of their respective births.

Now that our functions have persistent, private memories, what can we actually do with them? In the final part, we'll look at the "pro code" patterns that depend on this structure.

Further Reading and Watching