Loop variable scope issue with functions in JavaScript - need help

I’m running into a weird problem with JavaScript loops and functions. When I create functions inside a loop, they all seem to use the same variable value instead of keeping their own copy.

Here’s what I’m trying to do:

var actions = [];
// creating 3 different functions
for (var x = 0; x < 3; x++) {
  // storing them in the array
  actions[x] = function() {
    // want each to show its own number
    console.log("Number is:", x);
  };
}
for (var k = 0; k < 3; k++) {
  // running each function
  actions[k]();
}

But I get this result:

Number is: 3
Number is: 3
Number is: 3

What I actually want is:

Number is: 0
Number is: 1
Number is: 2

This same thing happens with click handlers too:

var elements = document.querySelectorAll("input");
for (var x = 0; x < elements.length; x++) {
  elements[x].onclick = function() {
    console.log("Clicked button:", x);
  };
}
<input type="button" value="First">
<input type="button" value="Second">
<input type="button" value="Third">

And with async stuff like timeouts:

const delay = (time) => new Promise(resolve => setTimeout(resolve, time));

for (var x = 0; x < 3; x++) {
  delay(x * 50).then(() => console.log(x));
}

Even happens in different types of loops:

const items = [5,10,15];
const callbacks = [];

for (var index in items){
  callbacks.push(() => console.log("at:", index));
}

for (var item of items){
  callbacks.push(() => console.log("item:", item));
}

for (const num of items) {
  var data = { value: num };
  callbacks.push(() => console.log("num:", num, "data:", JSON.stringify(data)));
}

for(var callback of callbacks){
  callback();
}

How do I fix this so each function remembers its own value?

This is a common closure issue that many developers encounter. The functions are capturing the same reference to the loop variable instead of its value at the time of creation. By the time the functions are executed, the loop has completed, resulting in all functions referencing the final value of the variable.

The simplest solution is to replace var with let in your loop. This creates a new scope for each iteration, allowing each function to access its own unique copy of the variable. Therefore, change for (var x = 0; x < 3; x++) to for (let x = 0; x < 3; x++). If you’re working in an older JavaScript environment that doesn’t support let, you can use an Immediately Invoked Function Expression (IIFE) to create a new scope for each iteration, passing the current value as a parameter.

Yeah, this tripped me up when I started too. All your functions reference the same x variable after the loop ends, so they see the final value (3). Easy fix with bind(): actions[x] = function(num) { console.log("Number is:", num); }.bind(null, x); This captures the current x value for each function.

I’ve hit this exact headache tons of times when starting out. What’s happening is all your functions share the same variable reference instead of capturing the value when they were created. It’s like everyone pointing to the same mailbox instead of taking their own snapshot.

Besides switching from var to let, you can wrap your function creation in a closure that grabs the current value immediately. Add an extra function layer that takes the current value as a parameter: actions[x] = (function(currentX) { return function() { console.log("Number is:", currentX); }; })(x); This creates a new scope each time and passes the current x value into it. More verbose than using let but shows you what’s really happening under the hood.