Javascript中使用“with”关键字的范围解析
当使用“with”关键字时,Javascript中似乎有一种奇怪的提升和作用域行为 我知道“with”的用法被认为是禁忌,但在其中一个框架中遇到了这种情况,因此不得不处理它。但尽管如此 有人能解释为什么如果我们有一个“with”块,那么声明但未定义的变量会使用with对象解析,但闭包变量不是这样 要演示,请参阅以下代码的输出: 通过谷歌浏览器检查 注意:我理解并理解为什么在警报后使用var语句是一个问题,但我想弄清楚的主要问题是, 在警报声明的范围解析过程中,由于吊装,“aptNum”和“x”应在局部范围内未定义,因此应视为“已声明但未定义” 但是,aptNum仍然作为“2”输出。来自fiddle:Javascript中使用“with”关键字的范围解析,javascript,jquery,google-chrome,javascript-engine,Javascript,Jquery,Google Chrome,Javascript Engine,当使用“with”关键字时,Javascript中似乎有一种奇怪的提升和作用域行为 我知道“with”的用法被认为是禁忌,但在其中一个框架中遇到了这种情况,因此不得不处理它。但尽管如此 有人能解释为什么如果我们有一个“with”块,那么声明但未定义的变量会使用with对象解析,但闭包变量不是这样 要演示,请参阅以下代码的输出: 通过谷歌浏览器检查 注意:我理解并理解为什么在警报后使用var语句是一个问题,但我想弄清楚的主要问题是, 在警报声明的范围解析过程中,由于吊装,“aptNum”和“x”应
with(address){
$('#output').text('aptNum : ' + aptNum + ", x : " + x );
var aptNum = 100,
x = 10 ;
}
变量x正在with语句体中重新声明,请参见前面的var关键字。变量声明被挂起,因此x被临时定义为未定义,然后在值被记录之后,最终被重新定义为10
在这个更新的fiddle中,我将变量声明语句更改为一个简单的赋值语句,这将产生预期的行为,将x的值记录为90。请参见fiddle的:
with(address){
$('#output').text('aptNum : ' + aptNum + ", x : " + x );
var aptNum = 100,
x = 10 ;
}
变量x正在with语句体中重新声明,请参见前面的var关键字。变量声明被挂起,因此x被临时定义为未定义,然后在值被记录之后,最终被重新定义为10
在这个更新的fiddle中,我将变量声明语句更改为一个简单的赋值语句,这将产生预期的行为,将x的值记录为90。请参见我猜您调用了x,它甚至在声明x之前就应该是address的属性。with作用域中的x不引用在函数外部声明的x。引擎正在尝试读取address.x的值,当然,该值不存在。这就是原因。关于,因为aptNum被“重新”声明为该范围内的变量,所以它不引用地址的aptNum。我猜您在声明x之前调用了x,它将被预期为地址的属性。with作用域中的x不引用在函数外部声明的x。引擎正在尝试读取address.x的值,当然,该值不存在。这就是原因。关于,由于aptNum被“重新”声明为该范围内的变量,因此它不引用地址的aptNum。代码
alert(aptNum + ":" + x);
var aptNum = 100,
x = 10 ;
是与中的aptNum和x的变量。var被提升,因此也可被视为
var aptNum, x;
alert(aptNum + ":" + x);
aptNum = 100, x = 10;
现在很容易理解为什么它们没有定义。您可能不想在这里使用var。代码
alert(aptNum + ":" + x);
var aptNum = 100,
x = 10 ;
是与中的aptNum和x的变量。var被提升,因此也可被视为
var aptNum, x;
alert(aptNum + ":" + x);
aptNum = 100, x = 10;
现在很容易理解为什么它们没有定义。您可能不想在这里使用var
不建议与一起使用,并且在ECMAScript 5严格模式下禁止使用。建议的替代方法是将要访问其属性的对象指定给临时变量
它不喜欢有一个全局变量。我认为这是因为x超出了address对象的范围。您可以将参数传递到函数中,它就可以工作了
var x = 90;
test(x);
例如:
更多关于
不建议与一起使用,并且在ECMAScript 5严格模式下禁止使用。建议的替代方法是将要访问其属性的对象指定给临时变量
它不喜欢有一个全局变量。我认为这是因为x超出了address对象的范围。您可以将参数传递到函数中,它就可以工作了
var x = 90;
test(x);
例如:
有关with的详细信息在with块中,变量aptNum被address.aptNum隐藏,而x指的是局部变量never address.x,因为没有这样的属性
考虑到这一点,您的代码相当于:
var x = 90;
function test1(){
var aptNum; // hoisted
var x; // hoisted
var address = {
street: 'Haight',
aptNum: 2
};
with (address){
// any reference to aptNum or street inside the with block
// is actually referencing address.aptNum and address.street
alert(aptNum + ":" + x); // this outputs 2 : undefined.
// as expected, because there is no address.x
// and the local x is undefined at this point
aptNum = 100; // this assigns to address.aptNum
// the variable aptNum is shadowed by address.aptNum
x = 10; // this assigns to the local x inside the function
// (again because there is no address.x)
}
}
在with块中,变量aptNum被address.aptNum隐藏,而x指的是局部变量never address.x,因为没有这样的属性
考虑到这一点,您的代码相当于:
var x = 90;
function test1(){
var aptNum; // hoisted
var x; // hoisted
var address = {
street: 'Haight',
aptNum: 2
};
with (address){
// any reference to aptNum or street inside the with block
// is actually referencing address.aptNum and address.street
alert(aptNum + ":" + x); // this outputs 2 : undefined.
// as expected, because there is no address.x
// and the local x is undefined at this point
aptNum = 100; // this assigns to address.aptNum
// the variable aptNum is shadowed by address.aptNum
x = 10; // this assigns to the local x inside the function
// (again because there is no address.x)
}
}
我不关心如何使x等于x。实际上,我试图在这里演示范围解析特性。问题是为什么x和aptnumx的分辨率不同,这已经通过在x上滥用var关键字来解释了。我不关心如何使x等于x。实际上,我试图在这里演示范围解析特性。问题是为什么x和aptnumx在分辨率上的差异已经通过在x上滥用var关键字来解释了。我明白你的意思。但是,使
有趣的是:aptNum不是作为“未定义”输出的。它正在解析address.aptNum中的值,即“2”,我明白你的意思。但有趣的是:aptNum并不是作为“未定义”输出的。它正在解析address.aptNum中的值,该值为“2”,JavaScript没有块作用域。with中的var aptNum是封闭函数的局部变量。提供给的对象的属性可以作为块中的变量访问,这就是为什么会得到2。您不能使用var向对象添加新属性,尽管您可以在不直接引用对象的情况下更新现有属性。@谢谢。这似乎以某种方式创建了一个块范围,其中在本地范围中填充了“with”对象属性。然后范围在块之后消失。但由于JS中没有块作用域,这是一种奇怪的行为,它的行为奇怪且令人困惑,这就是人们建议避免它的原因。不过,它可能很有用。它是一个范围,但不是一个典型的变量范围。var不受块的约束。JavaScript没有块作用域。with中的var aptNum是封闭函数的局部变量。提供给的对象的属性可以作为块中的变量访问,这就是为什么会得到2。您不能使用var向对象添加新属性,尽管您可以在不直接引用对象的情况下更新现有属性。@谢谢。这似乎以某种方式创建了一个块范围,其中在本地范围中填充了“with”对象属性。然后范围在块之后消失。但由于JS中没有块作用域,这是一种奇怪的行为,它的行为奇怪且令人困惑,这就是人们建议避免它的原因。不过,它可能很有用。它是一个范围,但不是一个典型的变量范围。var不受块的约束。因此,基本上,对于with块中的aptNum,它更新address.aptNum,但对于x,它更新本地“x”。如果我们检查块外x和aptNum的值,这就证明了这一点。谢谢这是有道理的,没错。它还证明了with语句是如何令人困惑的。因此,基本上,对于with块中的aptNum,它更新地址。aptNum但是对于x,它更新本地“x”。如果我们检查块外x和aptNum的值,这就证明了这一点。谢谢这是有道理的,没错。这也证明了with语句是如何令人困惑的。