JavaScripts with()语句中局部变量的行为
我注意到了一些奇怪的行为(据我所知,至少在ECMA 3.0规范中是未定义的行为),请看下面的代码片段:JavaScripts with()语句中局部变量的行为,javascript,jquery,Javascript,Jquery,我注意到了一些奇怪的行为(据我所知,至少在ECMA 3.0规范中是未定义的行为),请看下面的代码片段: var foo = { bar: "1", baz: "2" }; alert(bar); with(foo) { alert(bar); alert(bar); } alert(bar); 它在Firefox和Chrome中都会崩溃,因为第一个警报()中不存在“bar”;声明,这是意料之中的。但是,如果在with()-语句中添加一个bar声明,则它如下所示: var foo
var foo = { bar: "1", baz: "2" };
alert(bar);
with(foo) {
alert(bar);
alert(bar);
}
alert(bar);
它在Firefox和Chrome中都会崩溃,因为第一个警报()中不存在“bar”;声明,这是意料之中的。但是,如果在with()-语句中添加一个bar声明,则它如下所示:
var foo = { bar: "1", baz: "2" };
alert(bar);
with(foo) {
alert(bar);
var bar = "g2";
alert(bar);
}
alert(bar);
它将产生以下结果:
未定义,1,g2,未定义
似乎您在with()语句中创建了一个变量,大多数浏览器(在Chrome或Firefox上测试)也会使该变量存在于该范围之外,它只是设置为undefined。现在,从我的透视图来看,条形图应该只存在于with()-语句中,如果您让示例更奇怪:
var foo = { bar: "1", baz: "2" };
var zoo;
alert(bar);
with(foo) {
alert(bar);
var bar = "g2";
zoo = function() {
return bar;
}
alert(bar);
}
alert(bar);
alert(zoo());
它将产生以下结果:
未定义,1,g2,未定义,g2
因此with()-语句中的bar
并不存在于其外部,但运行时以某种方式“自动”创建了一个名为bar的变量,该变量在其顶级范围(全局或函数)中未定义,但该变量与with()-语句中的变量不同,并且该变量仅在with()语句中存在-语句中定义了一个名为bar的变量
非常奇怪,而且前后矛盾。有人对这种行为有什么解释吗?ECMA规范中没有这方面的内容。这是ECMA-262第三版第12.2节中的内容,如下所示 变量是在输入执行范围时创建的。块不定义新的执行范围 及 带有初始值设定项的变量在执行VariableStatement时,而不是在创建变量时,分配其AssignmentExpression的值 这意味着您必须将带有初始值设定项的声明视为两个独立的步骤:首先,在进入函数(执行脚本)时,在函数局部(全局)范围内创建一个新变量,但在到达语句之前,您不会赋值。在您的示例中,此时由于
with()
,作用域链已更改,赋值将看到重载变量,而新创建的变量未定义
这意味着
with({ foo : 42 }) {
var foo = 'bar';
}
被解析为
with({ foo : 42 }) {
var foo;
foo = 'bar';
}
这相当于
var foo;
({ foo : 42 }).foo = 'bar';
因此,未初始化
foo
。这是ECMA-262,第3版,§12.2中的如下内容:
变量是在输入执行范围时创建的。块不定义新的执行范围
及
带有初始值设定项的变量在执行VariableStatement时,而不是在创建变量时,分配其AssignmentExpression的值
这意味着您必须将带有初始值设定项的声明视为两个独立的步骤:首先,在进入函数(执行脚本)时,在函数局部(全局)范围内创建一个新变量,但在到达语句之前,您不会赋值。在您的示例中,此时由于with()
,作用域链已更改,赋值将看到重载变量,而新创建的变量未定义
这意味着
with({ foo : 42 }) {
var foo = 'bar';
}
被解析为
with({ foo : 42 }) {
var foo;
foo = 'bar';
}
这相当于
var foo;
({ foo : 42 }).foo = 'bar';
因此没有初始化
foo
。我想你只是对范围有点误解。我并不是在责怪你,如果你来自大多数其他语言,那你会说“WTF?”。Javascript有我称之为“FUBAR作用域”(我确信这里有一个合适的术语,但我从来没有费心去学习它……知道它是如何工作的>知道它叫什么,至少对我来说是这样)
:
with()
允许对变量进行块级定义,以便传递到作用域()。但是…它没有将变量限制在此范围内,它在之后可用:
如果with()
是您正在处理的元素的闭包,那么此
将引用我们传递到with()中的{bar:1}
对象,但它不是:)<代码>此在本例中仍然是窗口的全局上下文
。由于您仍在该上下文中执行,因此您定义的任何变量都将在该上下文中可用,因此在函数的with()
后面可用,因为它们的定义范围比您想象的要高得多。直觉告诉您它是在一个更受约束的范围内定义的:在with()
…但是javascript不同,它完全取决于闭包运行的上下文
我试图为这种行为找到一个好的描述,它提供了更多的范围示例。总的来说,这更像是一个闭包/范围问题,而不是with()
明确地说,这个网站更详细地介绍了整个概念,以防我解释得很糟糕……我知道这在很多方面都是一个落后的概念,对不起
我想你只是对范围有点误解。我并不是在责怪你,如果你来自大多数其他语言,那你会说“WTF?”。Javascript有我称之为“FUBAR作用域”(我确信这里有一个合适的术语,但我从来没有费心去学习它……知道它是如何工作的>知道它叫什么,至少对我来说是这样) :
with()
允许对变量进行块级定义,以便传递到作用域()。但是…它没有将变量限制在此范围内,它在之后可用:
如果with()
是您正在处理的元素的闭包,那么此
将引用我们传递到with()中的{bar:1}
对象,但它不是:)<代码>此在本例中仍然是窗口的全局上下文
。由于您仍在该上下文中执行,因此您在其中定义的任何变量都将在该上下文中可用,因此在函数后面的with()
之后可用,因为它们已定义