Javascript 功能范围 [Javascript 精要]

Javascript function scope [Javascript Essentials]

我正在观看 Travis Tidwell 的 Javascript Essentials,他在其中解释了这段代码:

(function() {
    var messages = ['hello', 'there'];

    for (var i in messages) {
        setTimeout(function() {
            console.log(messages[i]);
        }, 10); 
    };
})();

它在控制台中回显 'there' 两次,但我仍然不明白为什么。有人可以和我一起一步步过一遍javascript吗?

每次代码循环时,它都会设置一个事件处理程序,以便在 10 毫秒过去后,它会记录 messages[i] 的值。

在任何这些超时过去 10 毫秒之前,i 的值已更改(通过 for 循环)到 1(因为那是最后一个 属性数组中的名称)。

第一次超时然后输出messages[1],然后第二次超时输出messages[1].


  1. 数组已创建并存储在 messages
  2. i 设置为 0 并设置超时
  3. i 设置为 1 并设置超时
  4. 第一次超时函数运行,i仍然是1
  5. 第二次超时函数运行,i仍然是1

JavaScript 具有函数作用域,而不是像其他语言那样的块作用域。所以,实际上只存在一个 i 变量。当 setTimeout 中的代码被调用时,i 已经设置为数组的最后一个索引。

很快,在 ECMAScript 6 中,我们可以使用 let 声明块作用域变量。看这里:Mozilla Reference: let

到那时,解决此行为的方法之一是为需要独立于其他变量的变量创建一个新函数:

(function() {
  var messages = ['hello', 'there'];

  for (var i in messages) {
    (function(currentIndex) {
      setTimeout(function() {
        logToOutput(messages[currentIndex]);
      }, 10);
    })(i);
  };
})();

function logToOutput(msg) {
  document.getElementById("output").innerHTML += msg + "<br>";
}
<div id="output"></div>