🟒 EasyClosure TrapsπŸ› Debug Challenge

var in loop β€” buttons all say last value

Buggy Code β€” Can you spot the issue?

for (var i = 1; i <= 5; i++) {
  const btn = document.createElement('button');
  btn.textContent = `Button ${i}`;
  btn.onclick = function() {
    alert(`Button ${i}`);
  };
  document.body.appendChild(btn);
}

Fixed Code

// Fix 1: Use let (creates new binding per iteration)
for (let i = 1; i <= 5; i++) {
  const btn = document.createElement('button');
  btn.textContent = `Button ${i}`;
  btn.onclick = function() {
    alert(`Button ${i}`);
  };
  document.body.appendChild(btn);
}

// Fix 2: Use data attribute
for (var i = 1; i <= 5; i++) {
  const btn = document.createElement('button');
  btn.textContent = `Button ${i}`;
  btn.dataset.num = i;
  btn.onclick = function() {
    alert(`Button ${this.dataset.num}`);
  };
  document.body.appendChild(btn);
}

Bug Explained

Bug: var i is shared across all closures. By the time any button is clicked, i = 6 (loop finished).

Explanation: The simplest fix is let instead of var. let creates a new binding for each loop iteration, so each closure captures its own i.

Key Insight: This is the #1 most common closure bug in interviews. The fix: use let, or capture value in a data attribute.

More Closure Traps Debug Challenges

🟑 MediumStale closure in React useEffectβ†’πŸ”΄ HardMemoization closure caching wrong scopeβ†’πŸŸ‘ MediumPrivate variable accidentally exposedβ†’πŸŸ‘ MediumGenerator losing this contextβ†’

Practice spotting bugs live β†’

38 debug challenges with AI hints

πŸ› Try Debug Lab