Search code examples
javascriptscopeinternalsscope-chain

Where do invalid variables go when using JavaScript's with(){} statement?


When using JavaScript's with statement, where do variables that have invalid names go?

var o = {"@#$%":1,"test":2}

with(o){
  console.log(test)
  // Can't do this:
  //console.log(@#$%)
  // Was it not imported, or is it just inaccessible?
}

Can you reference the code in a JavaScript engine as well?


Solution

  • If a property is not a valid identifier, it can't be referenced like an identifier inside with. It's not inaccessible, but your only option is to look up the property on the original object manually, like normal:

    var o = {"@#$%":1,"test":2}
    
    with(o){
      console.log(o['@#$%']);
    }

    This sort of issue is not exclusive to the deprecated with statement. It occurs with the global object as well. Just like a with statement creates an object Environment Record, similarly, all code in a script is, in a sense, implicitly wrapped in a with for the global object (resulting in the global environment record).

    So, for exactly the same reasons, when a property which can't be an identifier is on window, eg:

    window['###'] = 'foo';

    There's no way to get to foo by using a standalone identifier without explicitly referencing window first (or use some other method to get to the global object).

    (of course, just like with with, properties which are valid as identifiers on window can be referenced standalone - that's why we can, for example, reference undefined and Array instead of window.undefined and window.Array. This can cause bugs...)