10

查看以下 HTML/Javascript 代码片段:

<html>
<head>
<script type="text/javascript">
var alerts = [];
for(var i = 0; i < 3; i++) {
    alerts.push(function() { document.write(i + ', '); });
}

for (var j = 0; j < 3; j++) {
    (alerts[j])();
}

for (var i = 0; i < 3; i++) {
    (alerts[i])();
}
</script>
</head><body></body></html>

这输出:

3, 3, 3, 0, 1, 2

这不是我所期待的 - 我期待输出0, 1, 2, 0, 1, 2,

我(错误地)假设被推入数组的匿名函数将表现为一个闭包,捕获在i创建函数时分配的值 - 但它实际上似乎i表现为一个全局变量。

谁能解释i这个代码示例中的范围发生了什么,以及为什么匿名函数没有捕获它的值?

4

2 回答 2

8

范围是定义变量的函数(除非没有,所以它是全局的)。

您传递的匿名函数正在访问在父函数(同样是全局)范围内定义的变量。

你需要一个实际的关闭。

alerts.push(
    function (foo) { 
        return function() { 
            document.write(foo + ', ');

        }
    }(i)
);
于 2010-04-28T22:00:11.390 回答
6

在 Javasript 中,唯一“有趣”的词法范围边界是函数体。在函数的任何地方声明的任何东西(嗯,除了另一个嵌套函数之外的任何地方!)都在同一范围内。关于声明的解释方式也有一些奇怪的事情。

您的匿名函数确实充当了一个闭包,但实例化的每个函数都将共享相同的“i”。我使用的一个技巧是添加另一层功能:

for (var i = 0; i < whatever; i++) {
  (function(idaho) {
    whatever(function() { alert("my own private " + idaho); });
  })(i);
}

希望在某个时候所有的浏览器都会支持新的“let”语句,这是一种更短、更不奇怪的方式来完成基本相同的事情。

于 2010-04-28T21:58:48.183 回答