每次都会发出以下警告2
。
function timer() {
for (var i = 0; i < 3; ++i) {
var j = i;
setTimeout(function () {
alert(j);
}, 1000);
}
}
timer();
不应var j = i;
将j
设置为setTimeout的各个范围吗?
然而,如果我这样做:
function timer() {
for (var i = 0; i < 3; ++i) {
(function (j) {
setTimeout(function () {
alert(j);
}, 1000);
})(i);
}
}
timer();
它会提醒0
,1
,2
。
我有什么遗失的吗?
答案 0 :(得分:29)
Javascript具有功能范围。这意味着
for(...) {
var j = i;
}
相当于
var j;
for(...) {
j = i;
}
实际上,这就是Javascript编译器实际处理此代码的方式。而且,当然,这会导致你的小“技巧”失败,因为j
会在调用setTimeout
中的函数之前递增,即j
现在并没有真正做任何不同的事情比i
,它只是一个具有相同范围的别名。
如果Javascript具有块范围,那么你的技巧就可以了,因为j
在每次迭代中都是一个新变量。
您需要做的是创建一个新范围:
for(var i = ...) {
(function (j) {
// you can safely use j here now
setTimeout(...);
})(i);
}
答案 1 :(得分:4)
IIFE的替代方案是功能工厂:
function timer() {
for (var i = 0; i < 3; ++i) {
setTimeout(createTimerCallback(i), 1000);
}
}
function createTimerCallback(i) {
return function() {
alert(i);
};
}
timer();
这就是说,这是javascript标签中最常见的问题之一。参见:
答案 2 :(得分:2)
另一种方法是使用(通常被滥用的)关键字with
:
function timer() {
for (var i = 0; i < 3; ++i) {
with({j: i}) {
setTimeout(function () {
alert(j);
}, 1000);
}
}
}
timer();
它创建了一个像函数一样的新范围,但没有笨拙的语法。我第一次看到它:Are there legitimate uses for JavaScript's “with” statement?