// Create 5 buttons, each should log its index
for (var i = 0; i < 5; i++) {
const btn = document.createElement('button');
btn.textContent = `Button ${i}`;
btn.addEventListener('click', function() {
console.log(i); // ALL print 5!
});
document.body.appendChild(btn);
}
var i is function-scoped, shared across all iterations. By the time any button is clicked, the loop has finished and i = 5.
All 5 click handlers close over the same variable. They don't capture the value at creation time — they capture a live reference to i.
for (let i = 0; i < 5; i++) {
// `let` is block-scoped — each iteration
// has its own `i`
// ... same code ...
// now logs 0, 1, 2, 3, 4 correctly!
}
Find the slider creation loop in PixelCraft. Replace var with let. Test all 8 sliders — each should now control its own filter independently.
function createFilterSlider(name, min, max, onChange) {
const slider = document.createElement('input');
slider.type = 'range';
slider.min = min;
slider.max = max;
slider.value = 0;
slider.addEventListener('input', function() {
onChange(parseInt(slider.value));
// `name` is captured in this closure
});
return slider;
}
function createCounter() {
let count = 0; // Private! Only the returned
// functions can access it.
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count,
};
}
count is truly private. No external code can access it. Only increment, decrement, and getCount — all closures — can read or modify it.
git switch -c bugfix/PIXELCRAFT-024-closure-bug
git add src/scripts/
git commit -m "Fix slider closure bug, var → let + factory pattern (PIXELCRAFT-024)"
git push origin bugfix/PIXELCRAFT-024-closure-bug
# PR → Review → Merge → Close ticket ✅
Closures exist in most modern languages.
A closure is a function + its lexical environment (the variables in scope when it was created).