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);
}// 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: 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.