问题
I'm having a problem with some JavaScript code.
Script
setTimeout(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?
回答1:
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?
回答2:
Take a look at this question. It might help you understand the scope and closures better, very similar to your question.
回答3:
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.
回答4:
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);
回答5:
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.
来源:https://stackoverflow.com/questions/1579978/javascript-variable-scope