运行以下代码:
for (var i=0; i<3; i++) {
setTimeout( function() { console.log(i); } , 500 );
}
输出“3”三次。在创建内部函数时,它输出的最终值为i
,而不是i
的值。
如果我希望输出为1,2和3,我该如何编写此代码?如何在定义函数时使用i
的值而不是其最终值?
答案 0 :(得分:6)
for (var i=0; i<3; i++) {
setTimeout( function(val) { return function() { console.log(val); } }(i), 500 );
}
因此,在setTimeout
时(在我们定义setTimeout
的函数时),我们将val
作为参数调用匿名函数。这为每个函数调用创建了一个闭包,将val
的值存储在我们刚刚调用的函数的范围内。我使用了self-invoking function,它会立即生成closure。
在您提供的代码中,代码创建了一个闭包,但是对于整个代码的较大范围,因此i
对于整个代码是本地的,这意味着在运行时,匿名函数将使用代码其余部分使用的变量i
。
答案 1 :(得分:4)
function f(i){
return function(){console.log(i);};
}
for (var i=0; i<3; i++) {
setTimeout(
f(i)
, 500 );
}
答案 2 :(得分:2)
显式闭包的现代替代方法(当你有双重包装函数时可能会有点毛茸茸的读取)是Function#bind
。对于尚未执行ECMAScript第五版的浏览器hacked in support,您可以说:
for (var i=0; i<3; i++) {
setTimeout(function(i) { console.log(i); }.bind(window, i), 500);
}
window
是函数内this
的值(这里不需要this
,所以我们只使用默认的全局对象)。如果您只是调用另一个函数/方法,就像使用console.log
一样,您可以使用它来完全删除函数表达式:
for (var i=0; i<3; i++) {
setTimeout(console.log.bind(console, i), 500);
}
答案 3 :(得分:1)
替代:
for (var i=0; i<3; i++) {
(function(val){
setTimeout(function() {
console.log(val);
},500)
}(i));
}