Javascript中的范围解析使用'with'关键字

时间:2013-05-15 23:25:05

标签: javascript jquery google-chrome javascript-engine

当使用'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'。

5 个答案:

答案 0 :(得分:2)

with区块内,变量aptNumaddress.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

有关JavaScript with

的更多信息

答案 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 ;

varaptNum - xwithvar已被悬挂,因此也可视为

var aptNum, x;
alert(aptNum + ":" +  x);
aptNum = 100, x = 10;

现在很容易理解它们为undefined的原因。您可能不想在这里使用var