Skip to main content

Command Palette

Search for a command to run...

Closure

Published
3 min readView as Markdown

1. 🔑 Definition of Closure

👉 A closure is created when a function “remembers” the variables from its lexical scope, even when that function is executed outside of its original scope.

  • Functions in JS always carry their lexical scope along with them.

  • This bundle (function + reference to outer scope) = Closure.


2. Basic Example

function outer() {
    let a = 10;
    function inner() {
        console.log(a); // inner "remembers" a
    }
    return inner;
}

const fn = outer();
fn(); // ✅ 10

Explanation

  1. outer() runs → creates a=10 and defines inner.

  2. outer() returns inner.

  3. Even though outer() has finished execution, inner still remembers a.

  4. This memory preservation is called a closure.


3. Why Closures Happen?

Because of:

  • Lexical Scope → function knows its parent environment.

  • Scope Chain → variable lookup goes outward.

  • Garbage Collector → JS keeps variables alive if they’re still referenced.


4. Real-Life Example (setTimeout)

function x() {
    let i = 1;
    setTimeout(function() {
        console.log(i); // remembers i
    }, 1000);
}
x(); // after 1 sec → 1

👉 Even after x() has finished, the callback inside setTimeout still remembers i.


5. Tricky Example – Closure in Loops

// Using var
for (var i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}
// Output: 4 4 4

// Using let
for (let i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}
// Output: 1 2 3

Why?

  • var → function-scoped → all callbacks share same i, which becomes 4 after loop ends.

  • let → block-scoped → each iteration has its own copy of i → closures preserve separate values.


6. Closure in Interview Questions

Example 1 – Function Returning Function

function makeCounter() {
    let count = 0;
    return function() {
        count++;
        return count;
    }
}

const counter1 = makeCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2

const counter2 = makeCounter();
console.log(counter2()); // 1

👉 Each call to makeCounter() creates a new closure with its own count.


Example 2 – Closure with setTimeout in loop (Fixing var)

for (var i = 1; i <= 3; i++) {
    (function(j) {
        setTimeout(function() {
            console.log(j);
        }, j * 1000);
    })(i);
}
// Output: 1 2 3

👉 We use an IIFE (Immediately Invoked Function Expression) to capture each value of i in a closure.


7. Use Cases of Closures

  1. Data hiding / Encapsulation

     function bankAccount(initialBalance) {
         let balance = initialBalance;
    
         return {
             deposit(amount) { balance += amount; },
             getBalance() { return balance; }
         };
     }
    
     const account = bankAccount(100);
     account.deposit(50);
     console.log(account.getBalance()); // 150
    
  2. setTimeout / async callbacks

  3. Function factories

  4. Memoization / caching


8. Visualization (Lexical Environment Chain)

Global LE
└── outer’s LE { a: 10 }
    └── inner’s LE { }

👉 Even after outer finishes, inner still has reference to outer’s LE.


9. Takeaways ✅

  • Closure = function + its lexical environment.

  • Functions “carry their scope” wherever they go.

  • Used for data hiding, async handling, callbacks, memoization.

  • Important for interview trick Qs (loops, setTimeout, counters).

More from this blog

Amit singh's blog

235 posts