Skip to main content

Benefits of closures

What a closure is

A closure is a function that "remembers" its lexical (outer) scope, even when it runs outside that scope.

More simply put:

A closure is a function's ability to reach variables from the place where it was created, not from where it is called.


Example 1 - basic

javascript
function outer() { let count = 0; function inner() { count++; console.log(count); } return inner; } const counter = outer(); counter(); // 1 counter(); // 2 counter(); // 3

What happens:

  • outer() returns inner();
  • inner() remembered the count variable from its lexical environment;
  • even after outer() has finished, count does not disappear;
  • this is exactly what a closure is, the function's "saved memory".

Example 2 - private variables

javascript
function createUser(name) { let score = 0; return { getName() { return name; }, addScore() { score++; }, getScore() { return score; } }; } const alice = createUser('Alice'); alice.addScore(); alice.addScore(); console.log(alice.getName(), alice.getScore()); // Alice 2

Here score is a private variable: it is not accessible from outside (alice.score does not exist), but is accessible from the getScore and addScore closures.

This is how encapsulation and private data are implemented without classes.


Example 3 - function generators (factories)

javascript
function makeMultiplier(factor) { return function(num) { return num * factor; }; } const double = makeMultiplier(2); const triple = makeMultiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15

factor "lives" inside each function. That is, each function "remembers" what multiplier it was created with.


Example 4 - event handlers

javascript
function setupButton(id) { let clicks = 0; document.getElementById(id).addEventListener('click', () => { clicks++; console.log(`Click on button ${id}: ${clicks}`); }); } setupButton('save'); setupButton('cancel');

Each handler "remembers" its own clicks variable, even after exiting setupButton.


Example 5 - caching (memoization)

javascript
function memoize(fn) { const cache = {}; return function(arg) { if (cache[arg]) { console.log('From cache:', arg); return cache[arg]; } const result = fn(arg); cache[arg] = result; console.log('Computed:', arg); return result; }; } const square = memoize(x => x * x); square(4); // Computed: 4 square(4); // From cache: 4

cache is preserved between calls through the closure.


How this works "under the hood"

When a function is created, JS forms a lexical environment - an object where all variables declared inside are stored.

If an inner function uses variables from an outer scope, it remembers a reference to that environment.

So even after the outer function finishes, the inner functions can still access its variables.


Closures are created automatically

You don't need to do anything special, every time you create a function inside another one, JS creates a closure.

javascript
function outer() { const a = 42; return function() { console.log(a); // closure }; }

Where closures are used in real life

ScenarioExample
Private dataHiding variables inside a function
Function factoriesGenerators, configurable handlers
Modules and encapsulationSplitting logic without global variables
Caching (memoization)Storing computation results
Counters and stateKeeping state between calls
Callbacks and event handlersAccess to outer data inside a function
Functional programmingCurrying, partial application, compose, etc.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.