Search code examples
javascriptjquerygoogle-chromejavascript-engine

Scope resolution in Javascript using 'with' keyword


There seems to be a strange behavior in Javascript with hoisting and scoping , when using 'with' keyword.

I understand the usage of 'with' is considered taboo, but came across this in one of the frameworks and had to deal with it. But nonetheless,

Could anyone explain why if we have a 'with' block , the variables that are declared but undefined are resolved using the with object but this is not the case with the closure variables.

To demo, see the output of the following code: 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 ;
    }
}

Checked with google chrome.

Note: that I understand JS hoisting and see why having var statements after the alert is an issue but the main thing I am trying to figure out it is , during scope resolution at the alert statement, both 'aptNum' and 'x' should be undefined in local scope due to hoisting, so they should be taken as 'declared but not defined'.

But still, aptNum is output as '2'.


Solution

  • Inside the with block, the variable aptNum is shadowed by address.aptNum, and x refers to the local variable (never address.x, as there isn't such a property).

    Considering that, and hoisting, your code is equivalent to:

    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)
        }
    }