🔒 Closures — The Magic of Remembering in JavaScript

pushpesh kumarpushpesh kumar
2 min read

Closures are one of the most fascinating (and sometimes confusing) concepts in JavaScript. But if you understand scope chain and lexical environment, closures become much easier to grasp. Let’s break it down with examples.

đź’ˇ What is a Closure?

A closure is a function that remembers its outer variables even after the outer function has finished execution. In other words, a closure gives you access to an outer function’s scope from an inner function.

đź§© Basic Example

function outer() {
  let outerVar = "I am outside!";

  function inner() {
    console.log(outerVar);
  }

  return inner;
}

const myClosure = outer();
myClosure(); // "I am outside!"

What’s happening?

  • outer() is called and returns inner function.

  • inner still has access to outerVar even though outer() has already finished executing.

🎯 Using Closures to Create Private Variables

function counter() {
  let count = 0;

  return function() {
    count++;
    console.log(count);
  };
}

const increment = counter();

increment(); // 1
increment(); // 2
increment(); // 3

Why it works

The count variable is in the lexical environment of the returned function. It is private and maintained across multiple calls.

đź§° Example: Factory Functions

function makeMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const double = makeMultiplier(2);
const triple = makeMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

Explanation

Each returned function "remembers" its own factor value, creating separate multiplier functions.

⚠️ Common Pitfall: Loops and Closures

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

Output

3
3
3

Why?

Because var is function-scoped and not block-scoped, all callbacks share the same i, which ends up as 3.

How to fix it?

Use let, which is block-scoped:

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

Correct Output

0
1
2

🌀 Returning Objects with Closures

function createPerson(name) {
  let age = 0;

  return {
    getName: function() {
      return name;
    },
    birthday: function() {
      age++;
    },
    getAge: function() {
      return age;
    }
  };
}

const person = createPerson("John");
console.log(person.getName()); // John
console.log(person.getAge()); // 0
person.birthday();
console.log(person.getAge()); // 1

Why it works

The returned object functions share access to name and age via closure.

âś… Key Takeaways

  • Closures allow functions to access outer scope variables even after the outer function has finished.

  • Useful for creating private data and factory functions.

  • Understand var vs let inside loops to avoid common mistakes.

0
Subscribe to my newsletter

Read articles from pushpesh kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

pushpesh kumar
pushpesh kumar