我的javascript范围有什么问题?

Nea*_*eal 50 javascript closures scope

2每次都会发出以下警报.

function timer() {
    for (var i = 0; i < 3; ++i) {
        var j = i;
        setTimeout(function () {
            alert(j);
        }, 1000);
    }
}

timer();
Run Code Online (Sandbox Code Playgroud)

不应该var j = i;设置j进入setTimeout的个别范围?

如果我这样做:

function timer() {
    for (var i = 0; i < 3; ++i) {
        (function (j) {
            setTimeout(function () {
                alert(j);
            }, 1000);
        })(i);
    }
}

timer();
Run Code Online (Sandbox Code Playgroud)

它提醒0,1,2像它应该.

有什么我想念的吗?

Ing*_*ürk 30

Javascript具有功能范围.这意味着

for(...) {
    var j = i;
}
Run Code Online (Sandbox Code Playgroud)

相当于

var j;
for(...) {
    j = i;
}
Run Code Online (Sandbox Code Playgroud)

实际上,这就是Javascript编译器实际处理此代码的方式.而且,当然,这会导致你的小"技巧"​​失败,因为jsetTimeout调用函数之前会增加,即j现在并没有真正做任何不同的事情i,它只是具有相同范围的别名.

如果Javascript具有块范围,那么你的技巧就可以了,因为j在每次迭代中它都是一个新的变量.

您需要做的是创建一个新范围:

for(var i = ...) {
    (function (j) {
        // you can safely use j here now
        setTimeout(...);
    })(i);
}
Run Code Online (Sandbox Code Playgroud)


bfa*_*tto 5

IIFE的替代方法是功能工厂:

function timer() {
    for (var i = 0; i < 3; ++i) {
        setTimeout(createTimerCallback(i), 1000);
    }
}

function createTimerCallback(i) {
    return function() {
       alert(i);
    };
}

timer();
Run Code Online (Sandbox Code Playgroud)

话虽如此,这是javascript标记中最常问到的问题之一。看到:

  • 这不是 hacky,这只是作用域在这种语言中的工作原理。 (2认同)