How a function keeps access to variables from a scope that's technically already gone.
A closure happens whenever a function retains access to variables from its enclosing scope, even after that outer function has finished running. This isn't a special feature you opt into — it's just how lexical scoping works in JavaScript: a function remembers the environment it was created in, not the environment it's called from, and that environment stays alive as long as something still references it.
Closures are the mechanism behind private state (data hidden inside a function, only accessible through returned methods), memoization, and the module pattern — but they also have a well-known trap: variables declared with var inside a loop are shared across every closure created in that loop, so all of them end up referencing the same final value. let fixes this by creating a new binding per iteration, which is one of the clearest practical differences between var and let.
What you'll walk away knowing