JavaScript /循环混乱中的动态与词汇作用域

时间:2015-02-25 21:53:37

标签: javascript for-loop scope

我遇到了一个细微的错误,已按如下方式提取:

function huh() {
    for (var i = 0; i < 10; i++) {
        if ( i % 2 == 1 ) {
            var x = i;
            console.log(i + ' ' + x);
        }
        else {
            console.log(i + ' ' + x);
        }
    }
}

huh();

首先,我会挑战即使是经验丰富的JavaScript程序员,也只是在纸上正确预测该程序的确切输出。但主要是,JavaScript似乎混合了动态和词汇范围。似乎没有块范围,只有功能范围,这基本上吹走了我在JavaScript中的整个范围概念。有人可以参考标准解释,也许有点理由吗?这似乎非常反直觉。

2 个答案:

答案 0 :(得分:1)

使用let关键字从ecmascript版本6开始使用JavaScript进行块定义。

除此之外,它与var语句一起使用的方式是在执行函数之前语句浮动到函数的顶部。变量声明在其他任何内容之前发生,无论它们在哪个块中,包括for循环语句内部。变量的实际赋值确实发生了,所以它们是未定义的,但是在它们被赋值的代码行之前不会被声明。

至于你的具体例子,请记住像数字这样的原始值不是通过引用而是通过值分配的,并且x的更新只会发生在不均匀的数字上,并且在第一轮时将是未定义的,但是如果它是对象,一旦你将一个对象分配给另一个对象,它们就会引用同一个对象(无论if / else条件如何)。

为了提供进一步的混淆,请注意浏览器中的控制台是异步的,因此您可以将对象打印到控制台(尽管不是基元)并检查它们在{{1}时无法获得对象状态的位置声明,但在以后的时间。这对调试非常困惑。

是的JavaScript在实践中肯定有一点学习曲线。

答案 1 :(得分:1)

这种有点令人费解的效果是功能范围variable hoisting的组合。

您应该考虑上述代码等同于:

function huh() {
  var i, x;
  for (i = 0; i < 10; i++) {
    if ( i % 2 == 1 ) {
      x = i;
      console.log(i + ' ' + x);
    }
    else {
      console.log(i + ' ' + x); }
  }
}