What is wrong with my javascript scope?
本问题已经有最佳答案,请猛点这里访问。
以下内容每次都会提醒
1 2 3 4 5 6 7 8 9 10 | function timer() { for (var i = 0; i < 3; ++i) { var j = i; setTimeout(function () { alert(j); }, 1000); } } timer(); |
难道
如果我这样做:
1 2 3 4 5 6 7 8 9 10 11 | function timer() { for (var i = 0; i < 3; ++i) { (function (j) { setTimeout(function () { alert(j); }, 1000); })(i); } } timer(); |
它会像应该的那样提醒
我有什么东西不见了吗?
javascript具有功能范围。这意味着
1 2 3 | for(...) { var j = i; } |
等于
1 2 3 4 | var j; for(...) { j = i; } |
事实上,这就是JavaScript编译器实际处理此代码的方式。当然,这会导致你的小"诡计"失败,因为
如果Javascript有块范围,那么您的技巧就可以了,因为
您需要做的是创建一个新的作用域:
1 2 3 4 5 6 | for(var i = ...) { (function (j) { // you can safely use j here now setTimeout(...); })(i); } |
IIFE是一个功能工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function timer() { for (var i = 0; i < 3; ++i) { setTimeout(createTimerCallback(i), 1000); } } function createTimerCallback(i) { return function() { alert(i); }; } timer(); |
也就是说,这是javascript标记中最常见的问题之一。见:
- 循环内的javascript闭包——简单的实践示例
- javascript臭名昭著的循环问题?
另一种方法是使用(通常被滥用)关键字
1 2 3 4 5 6 7 8 9 10 11 | function timer() { for (var i = 0; i < 3; ++i) { with({j: i}) { setTimeout(function () { alert(j); }, 1000); } } } timer(); |
它创建了一个与函数类似的新范围,但没有笨拙的语法。我在这里第一次看到:javascript的"with"语句有合法的用途吗?