开发者

JavaScript Variable Scope [duplicate]

This question already has answers here: JavaScript closure inside loops – simple practical example (44 answers) Closed 8 years ago.

I'm having a problem with some JavaScript code.

Script

setTimeo开发者_JS百科ut(function() {
    for (var i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(i);
        }, i * 200);
    }
}, 200);

Outputs

5, 5, 5, 5, 5 instead of 1, 2, 3, 4, 5

I can kind of understand why this doesn't work, but I was wondering if someone could explain to me what's happening and why it's not working!

Also, how can this scope problem be overcome?


The setTimeout callback functions are executed asynchronously, all the console.log calls you make refer to the same i variable, and at the time they are executed, the for loop has ended and i contains 4.

You could wrap your inner setTimeout call inside a function accepting a parameter in order to store a reference to all the i values that are being iterated, something like this:

setTimeout(function() {
    for (var i = 0; i < 5; i++) {
      (function (j) { // added a closure to store a reference to 'i' values
        setTimeout(function() {
            console.log(j);
        }, j * 200);
      })(i); // automatically call the function and pass the value
    }
}, 200);

Check my answer to the following question for more details:

  • Variables in Anonymous Functions — Can someone explain the following?


Take a look at this question. It might help you understand the scope and closures better, very similar to your question.


You're trying to create a closure containing the variable "i". But closures are only created at the end of a function. So if your functions are created in a for loop, they will all have the values from the last iteration.

You can fix it with something like this:

var createFunction = function(index) {
  return function() {
    console.log(index);
  }
};

for (var i = 0; i < 5; i++) {
  setTimeout(createFunction(i), i * 200);
}

where you return the function from another function.


The variable i exists in the scope of the outer function.

It changes as the loop runs.

The inner function references it.

Try something like this:

var i_print_factory = function (value) {
  return function () {
    console.log(value);
  };
};

var init_timers = function () {
  for (var i = 0; i < 5; i++) {
    setTimeout(i_print_factory(i), i * 200);
  }
};

setTimeout(init_timers, 200);


Because you are accessing the same variable i in all the functions used in set timeout. The setTimeout function sets the function to fire the number of milliseconds in the future on the same thread as the i variable. The i value isn't copied in the function, the function is referencing the actual variable i when it is fired. Because you have looped through parent function until the i = 5 and this is done before anything else has a chance to fire, they all show up as 5.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜