2009-10-16 166 views
2

我遇到了一些JavaScript代码的问题。JavaScript可变范围

脚本

setTimeout(function() { 
    for (var i = 0; i < 5; i++) { 
     setTimeout(function() { 
      console.log(i); 
     }, i * 200); 
    } 
}, 200); 

输出

5,5,5,5,5,而不是1,2,3,4,5

我种理解为什么这不起作用,但我想知道是否有人能向我解释发生了什么,以及为什么它不起作用!

此外,如何克服这个范围问题?

回答

5

setTimeout回调函数是异步执行的,所有的console.log电话你让指同一i变量,并在它们被执行时,for循环已经结束i包含4个。

你可以换一个函数里你的内心setTimeout呼叫接受一个参数,以存储正在迭代所有i值的参考,像这样:

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); 

检查我的回答如下更多细节问题:

+0

感谢您的回复并回答了其他问题!它完美地解释了它! – 2009-10-18 13:10:50

+0

@Bisbo:不客气,很高兴帮助! – CMS 2009-10-20 06:42:37

+0

@bdukes:回滚编辑,'i'的最后一个值是'4',注意for循环中的'i <5'条件。 – CMS 2009-10-20 06:44:08

0

因为您正在访问设置超时中使用的所有函数中的相同变量i。 setTimeout函数将该函数设置为在与i变量相同的线程上触发将来的毫秒数。 i值不会复制到函数中,函数会在引发时引用实际变量i。因为您已经通过父功能循环,直到i = 5,并且在其他任何事情有机会触发之前完成,它们全部显示为5.

2

看一看this question。它可以帮助你更好地理解范围和封闭性,非常类似于你的问题。

+0

感谢伟大的链接!它完美地解释它! – 2009-10-18 13:09:52

1

变量i存在于外部函数的范围内。

它随循环运行而变化。

内部函数引用它。

尝试这样:

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); 
2

你想创建一个封闭包含变量“i”。但是闭包只能在函数结尾创建。因此,如果您的函数是在for循环中创建的,则它们都将具有上次迭代的值。

你可以用这样的修正:

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

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

,你从另一个函数返回的功能。