JavaScript 中的动态与词法范围/循环混淆
Dynamic vs. lexical scoping in JavaScript / loop confusion
我遇到了一个微妙的错误,提炼如下:
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 中的整个作用域概念。有人可以参考标准进行解释,也许还有一些理由吗?这似乎非常违反直觉。
从 ecmascript 版本 6 开始,JavaScript 中使用 let
关键字进行了块范围界定。
除此之外,它与 var
语句一起工作的方式是语句在函数执行之前浮动到函数的顶部。变量声明发生在其他任何事情之前,无论它们位于哪个块中,包括 for 循环语句内部。变量的实际赋值确实发生在适当的位置,因此它们是未定义的,但不是未声明的,直到它们被赋值的代码行。
至于你的具体例子,请记住像数字这样的原始值不是通过引用而是通过值分配的,并且 x
的更新只会发生在奇数上并且第一次是未定义的,但如果它是对象,一旦您将一个对象分配给另一个对象(无论 if/else 条件如何),它们将引用同一个对象。
为了进一步混淆,请注意浏览器中的控制台是异步的,因此您可以将对象打印到控制台(虽然不是原语)并在您无法获得对象状态的地方检查它们 console.log
语句,但在稍后的时间。这对于调试来说非常混乱。
是的JavaScript在实践中肯定有一点学习曲线。
这个有点令人费解的效果是函数作用域和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); }
}
}
我遇到了一个微妙的错误,提炼如下:
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 中的整个作用域概念。有人可以参考标准进行解释,也许还有一些理由吗?这似乎非常违反直觉。
从 ecmascript 版本 6 开始,JavaScript 中使用 let
关键字进行了块范围界定。
除此之外,它与 var
语句一起工作的方式是语句在函数执行之前浮动到函数的顶部。变量声明发生在其他任何事情之前,无论它们位于哪个块中,包括 for 循环语句内部。变量的实际赋值确实发生在适当的位置,因此它们是未定义的,但不是未声明的,直到它们被赋值的代码行。
至于你的具体例子,请记住像数字这样的原始值不是通过引用而是通过值分配的,并且 x
的更新只会发生在奇数上并且第一次是未定义的,但如果它是对象,一旦您将一个对象分配给另一个对象(无论 if/else 条件如何),它们将引用同一个对象。
为了进一步混淆,请注意浏览器中的控制台是异步的,因此您可以将对象打印到控制台(虽然不是原语)并在您无法获得对象状态的地方检查它们 console.log
语句,但在稍后的时间。这对于调试来说非常混乱。
是的JavaScript在实践中肯定有一点学习曲线。
这个有点令人费解的效果是函数作用域和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); }
}
}