当使用'with'关键字时,Javascript中似乎存在一种带有提升和范围的奇怪行为。
我理解'with'的用法被认为是禁忌,但在其中一个框架中遇到过这种情况并且必须处理它。但是,
有人可以解释为什么如果我们有一个'with'块,声明但未定义的变量使用with对象解析,但闭包变量不是这种情况。
要演示,请参阅以下代码的输出:http://jsfiddle.net/ftK2Z/1/
var x = 90;
function test1(){
var address = {
street: 'Haight',
aptNum: 2
};
with (address){
alert(aptNum + ":" + x); // this outputs 2 : undefined.
var aptNum = 100,
x = 10 ;
}
}
使用谷歌浏览器检查。
注意:我理解JS提升并了解为什么在警报之后使用var语句是一个问题,但我想弄清楚的主要是, 在alert语句的范围解析期间,由于提升,'aptNum'和'x'都应在本地范围内未定义,因此它们应被视为'声明但未定义'。
但是,aptNum输出为'2'。
答案 0 :(得分:2)
在with
区块内,变量aptNum
被address.aptNum
遮蔽,x
引用局部变量(从不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)
}
}
答案 1 :(得分:1)
来自小提琴:
with(address){
$('#output').text('aptNum : ' + aptNum + ", x : " + x );
var aptNum = 100,
x = 10 ;
}
变量x
正在with
语句的正文中重新声明(请参阅前面的var
关键字)。变量声明被提升,因此x
暂时定义为undefined
,然后在记录了值后最终重新定义为10
。
在这个更新的小提琴中,我将变量声明语句更改为一个简单的赋值语句,该语句产生将x
的值记录为90
的预期行为。见http://jsfiddle.net/ftK2Z/3/
答案 2 :(得分:1)
建议不要使用with,并且在ECMAScript 5严格模式下禁止使用。建议的替代方法是将要访问其属性的对象分配给临时变量。
它不喜欢拥有全局变量。我认为这是因为x超出了地址对象的范围。您可以将参数传递给函数,它可以正常工作。
var x = 90;
test(x);
示例:jsFiddle
的更多信息答案 3 :(得分:0)
我猜你甚至在声明x
之前就调用了address
(预计会被x
作为属性)。 x
范围中的with
未引用在函数外声明的x
。当然,引擎正试图读取不存在的address.x
的值。这就是原因。关于with
,由于aptNum
被're'声明为该范围内的变量,因此它不会引用address
的{{1}}。
答案 4 :(得分:0)
代码
alert(aptNum + ":" + x);
var aptNum = 100,
x = 10 ;
在var
内aptNum
- x
和with
。 var
已被悬挂,因此也可视为
var aptNum, x;
alert(aptNum + ":" + x);
aptNum = 100, x = 10;
现在很容易理解它们为undefined
的原因。您可能不想在这里使用var
。