Skip to content
jsworkbench.
Learning path
Intermediate20 minLESSON 13 / 34

Closures

01

Understand the idea

A click handler needs to remember how many times it has run, but resetting a local on every click keeps the count stuck at one.

A backpack that stays with the function

Why keep anything after a function returns? A click handler may need a counter between clicks, or a search helper may need a chosen delay. Making all that data global would let unrelated code change it. The backpack lets the function keep just the surroundings it needs.

Two calls, two sets of bindings

The outer call has two jobs: establish its local bindings and create the inner function. The inner function can use those bindings because it was defined inside that scope. Returning the function gives the caller a way to do that work later, without exposing a direct name for the private count.

Creating a function and calling it are separate events. makeCounter creates the inner increment function and returns it without calling it. The next binding then holds that function. Only next() performs an increment. A second call to makeCounter would create a second count and another backpack; it would not reset the first.

Which counter binding does each call use?
OperationWhich state it usesWhat happens
makeCounter()A new outer call’s countCreates a function with its own retained access
First next()The first counter’s existing countChanges 0 to 1
Second next()That same countChanges 1 to 2
Another makeCounter()A separate countCreates independent state starting at 0
Two inner functions from one outer callA shared outer bindingCan observe each other’s updates

What the backpack actually keeps

A binding can survive after its creating call has left the active call stack. It remains available while a reachable function still needs access to it. This retained access is what allows a second click to continue where the first left off.

The backpack is a mental model for retained access, not a literal copy of every value. If two inner functions share one outer binding, a change made through one is visible to the other. This explains why a closure can track changing state instead of always reporting its original value.

Useful private state

This makes closures useful for private counters, configured helpers, and handlers attached to a specific item. Two returned functions from the same outer call can deliberately cooperate through one count. Two separate outer calls have separate local bindings, so creating another counter does not reset the first.

Follow creation separately from use

Closures do not require returning a function; event handlers and can close over surrounding bindings too. They are useful, but they can also keep large reachable longer than expected. Remove unused handlers and timers so an otherwise finished feature can release the state it no longer needs.

Trace the example in two phases. During setup, count starts at zero and next receives the returned function. Later, the first next() changes that same count to one; the second changes it to two. count is not directly readable outside makeCounter, but increment still has access. If that distinction takes a second read, that is the useful part to slow down on.

02

Mental model

LEXICAL ENVIRONMENTmakeCounter → next
makeCounter() scope
count = 0

Outer function is running

next()

Inner function

A new lexical environment is created for this invocation.

01 / 07Call makeCounter()

03

Live example

makeCounter runs once. The returned runs twice and keeps using the same count, so the second result is 2.

Opening editor…
LIVE PREVIEW
Console 0

Your console output appears here.

Saved on this deviceJavaScript · ES2022
04

Guided challenge

Keep the remembered count

Increment the retained binding on each call instead of assigning the same value every time.

Opening editor…
LIVE PREVIEW
Console 0

Your console output appears here.

Saved on this deviceJavaScript · ES2022

EXPECTED CONSOLE OUTPUT

1
2

Hints 0/2

    Use all hints or make 3 failed runs (0/3).

    05

    Free sandbox

    Make a variation, test an assumption, or break the example on purpose. This draft is saved separately.

    Opening editor…
    LIVE PREVIEW
    Console 0

    Your console output appears here.

    Saved on this deviceJavaScript · ES2022
    06

    Quiz

    A quick check for understanding. Retry as often as you like; your learning path stays open.

    01What does the returned increment function retain?
    02What happens after two separate calls to makeCounter?

    Ready to call this one understood?

    Mark this lesson complete to earn 150 XP. You can always revisit it.

    Sign in to save progress
    Next lesson