What is the Closure in JavaScript?

A closure is a function that has access to its own scope, its outer function's scope (even after that function has finished running), and the global scope.

Every JavaScript function creates a new lexical environment. This environment has a reference to its outer environment, forming a scope chain

The scope chain is a process of how Javascript looks for variables. When code needs to access a variable, JavaScript looks at the current scope. If not found, it moves up the scope chain to the outer scope and continues until it reaches the global scope. If the variable is still not found, a reference error is thrown.

Closures can be used to emulate private properties and methods.

Mental Model

Functions in JavaScript remember where they were born.

Think of a closure like a backpack. When a function is created, it packs up all the variables it needs from its surrounding scope.

Wherever that function goes, the backpack comes along.

Example with Counter

function getCounter() {
  // counter is a local variable to the getCounter function
  let counter = 0; 

  return function () {
    // the returned function has access to the counter variable
    return counter++;
  };
}

let count = getCounter();
console.log(count()); // 0
console.log(count()); // 1
console.log(count()); // 2

Why this works?

When a function is created in JavaScript, it holds a reference to its lexical environment — the scope in which it was defined. That environment keeps variables alive as long as something (a closure) still references them.

Real World Example with Private Methods and Properties

We can use closures to create private methods and properties.

function createUser(name) {
  let _name = name; // "private"

  return {
    getName: () => _name,
    setName: (n) => (_name = n),
  };
}

const user = createUser("John");
console.log(user.getName()); // "John"

user.setName("Jane");
console.log(user.getName()); // "Jane"

Here we have a function createUser that creates a user object with a private name property. The getName and setName methods are closures that have access to the _name variable.

On Interviews

Interviewer can provide a code snippet and ask you to guess the output and explain why.

Classic closure bug with var in loops

Let's try to figure out what will this code print:

for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 100);
}

Here are two things:

  • We should guess what will the output of this code and describe why
  • We should tell what we should change to get the expected output

Current Output

Because var is function-scoped. The callback closes over the same i, and by the time it runs, the loop has completed, so the value of i is 3.

Output: 
3
3
3

Expected Output

To solve this problem, we can use let instead of var. let is block-scoped, so the callback will close over a new i for each iteration of the loop.

for (let i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 100);
}

// Output:
0
1
2

Summary

  • A closure is a function that "remembers" the scope from the place where it was created — even after that outer scope is gone.
  • Closures are created every time a function is created, at function creation time.
  • Closures use cases: private variables, event handlers, callbacks, currying, memoization, etc.
  • Mental model: Functions in JavaScript remember where they were born.

Related Topics

References