JavaScript Closure Inside Loops: A Common Pitfall Explained

One of the most misunderstood concepts in JavaScript—especially for beginners—is closure behavior inside loops. If you’ve ever used a for loop and tried to run setTimeout or another asynchronous function inside it, only to get unexpected results, you’re not alone.

In this article, we’ll break down why closures behave the way they do inside loops, the difference between var and let, and how to fix common issues developers encounter.


📌 What is a Closure in JavaScript?

A closure is created when a function retains access to variables from its outer scope, even after that outer function has finished executing. Here’s a quick example:

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

const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2

The function inner() is a closure because it “remembers” the variable count from its parent scope.


🔁 Closures in Loops: The Problem

Consider the following example using var inside a for loop:

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

Expected Output:

0
1
2

Actual Output:

3
3
3

Why? Because var is function-scoped, not block-scoped. All three closures inside the loop reference the same i, which after the loop ends, is 3.


✅ The Solution: Use let (Block Scope)

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

Output:

0
1
2

Using let creates a new scope for each iteration of the loop. Each setTimeout closure captures its own copy of i.


⚠️ Alternative Fix: IIFE (Immediately Invoked Function Expression)

Before let was introduced, developers used an IIFE to capture the current loop value:

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

The IIFE creates a new function scope where j takes the current value of i, preserving it for the closure.


🧠 Best Practices


📚 Final Thoughts

Understanding how closures work inside JavaScript loops helps you avoid mysterious bugs and write more predictable, maintainable code. By using let or wrapping logic in closures (IIFEs), you ensure each iteration of your loop behaves the way you expect.

Latest blog posts

Explore the world of programming and cybersecurity through our curated collection of blog posts. From cutting-edge coding trends to the latest cyber threats and defense strategies, we've got you covered.