A closure is a function that retains access to variables from its outer (enclosing) scope even after the outer function has returned, enabled by JavaScript's lexical scoping.
A closure is a function bundled with a reference to its outer scope — it retains access to those variables even after the outer function returns.
Closures create truly private variables that can only be accessed through the returned functions, not directly from outside.
Outer functions return specialized inner functions that remember the arguments passed to the outer function via the closure.
var is function-scoped so loop callbacks share one variable; let creates a new binding per iteration, giving each callback its own copy.
An IIFE returns an object with methods that access private variables in the closure — the encapsulation pattern used before ES modules.
A closure is created when a function is defined inside another function and references variables from the outer function's scope. The inner function "closes over" those variables, keeping them alive in memory even after the outer function has finished executing. Every function in JavaScript forms a closure, but the term is most meaningful when an inner function outlives its outer function.
JavaScript uses lexical scoping — variable access is determined by where functions are written in the source code, not where they are called. When a function is created, it gets a hidden reference to its lexical environment (the scope chain at the point of definition). When the function later executes and references a variable, JavaScript walks up this scope chain: local scope first, then each enclosing scope, up to the global scope.
Data privacy and encapsulation: Closures create truly private variables. A function can return an object with methods that access variables in the closure, but those variables cannot be accessed directly from outside. This was the primary encapsulation mechanism before ES modules and class private fields (#field).
Function factories: A function that returns a specialized function based on its arguments. For example, function makeMultiplier(x) { return y => x * y; } creates double = makeMultiplier(2) and triple = makeMultiplier(3) — each closure remembers its own x.
State preservation: Closures maintain state between calls without global variables. A counter function can keep its count in the closure, incrementing on each call while keeping the count inaccessible from outside.
Callbacks and event handlers: When you pass a function as a callback, it carries its closure with it, preserving access to surrounding variables at the time of creation.
This is the most frequently asked closure interview question. With var in a for-loop, setTimeout callbacks all share the same i variable (function-scoped), so they all print the final value. With let, each iteration creates a new block-scoped i, so each callback captures its own copy. Before let existed, the fix was wrapping each iteration in an IIFE: (function(j) { setTimeout(() => console.log(j), 0); })(i).
Before ES modules, closures powered the module pattern: an IIFE returns an object exposing public methods while keeping internal state private in the closure. const counter = (function() { let count = 0; return { increment() { return ++count; }, value() { return count; } }; })(); — count is inaccessible from outside, but increment and value can read and modify it through the closure.
Closures keep their entire lexical environment alive as long as the inner function exists. This is usually fine, but can cause memory issues if a closure unintentionally captures a large object or DOM node that would otherwise be garbage collected. Modern engines like V8 optimize this by only retaining variables that the inner function actually references, but it's worth being aware of when debugging memory leaks.
A closure is not just a function — it's a function plus its lexical environment. The function remembers the variables from the scope where it was created, not where it is called. This is the fundamental concept that enables data privacy, state preservation, and the module pattern in JavaScript.
Fun Fact
The term 'closure' was coined by Peter Landin in 1964 to describe a function paired with its referencing environment — decades before JavaScript existed. JavaScript popularized closures in mainstream programming when Douglas Crockford championed them as the key to the module pattern.