Yet it feels kind of hidden, almost magical. And it’s often talked about in either very abstract or very informal terms, which does little to help us nail down exactly what it is.

    We need to be able to recognize where closure is used in programs, as the presence or lack of closure is sometimes the cause of bugs (or even the cause of performance issues).

    So let’s define closure in a pragmatic and concrete way:

    We see two definitional characteristics here. First, closure is part of the nature of a function. Objects don’t get closures, functions do. Second, to observe a closure, you must execute a function in a different scope than where that function was originally defined.

    First, the outer function is executed, creating an instance of the inner function who(..); that function closes over the variable msg, which is the parameter from the outer scope of greeting(..). When that inner function is returned, its reference is assigned to the hello variable in the outer scope. Then we call greeting(..) a second time, creating a new inner function instance, with a new closure over a new msg, and return that reference to be assigned to howdy.

    When the greeting(..) function finishes running, normally we would expect all of its variables to be garbage collected (removed from memory). We’d expect each msg to go away, but they don’t. The reason is closure. Since the inner function instances are still alive (assigned to hello and , respectively), their closures are still preserving the msg variables.

    These closures are not a snapshot of the msg variable’s value; they are a direct link and preservation of the variable itself. That means closure can actually observe (or make!) updates to these variables over time.

    Each instance of the inner increaseCount() function is closed over both the count and step variables from its outer counter(..) function’s scope. step remains the same over time, but count is updated on each invocation of that inner function. Since closure is over the variables and not just snapshots of the values, these updates are preserved.

    Closure is most common when working with asynchronous code, such as with callbacks. Consider:

    It’s not necessary that the outer scope be a function—it usually is, but not always—just that there be at least one variable in an outer scope accessed from an inner function:

    Because this loop is using let declarations, each iteration gets new block-scoped (aka, local) idx and btn variables; the loop also creates a new inner onClick(..) function each time. That inner function closes over idx, preserving it for as long as the click handler is set on the btn. So when each button is clicked, its handler can print its associated index value, because the handler remembers its respective idx variable.

    Remember: this closure is not over the value (like 1 or ), but over the variable idx itself.

    Closure is one of the most prevalent and important programming patterns in any language. But that’s especially true of JS; it’s hard to imagine doing anything useful without leveraging closure in one way or another.

    If you’re still feeling unclear or shaky about closure, the majority of Book 2, Scope & Closures is focused on the topic.