A fun little spec deviation in the major JS engines

# Jeff Walden (14 years ago)

At least, if you consider |with| and |eval| fun (and who doesn't?):

js> var x = "outer"; function f() { with({ x: 17 }) eval("var x"); return x; } typeof f() "undefined"

This seems to be the behavior in every engine out there. But according to the last ES5 errata for 10.5, and in the latest ES6 draft, since "x" has a binding in the object environment record created when executing the |with| statement's substatement, and the object supplied to the |with| isn't the global object, the |var x| should do nothing whatsoever. Presumably given this implementation unanimity the spec should change on this point.

In a certain sense this was flagged in mail.mozilla.org/pipermail/es5-discuss/2011-January/003882.html in acknowledging the current language to be narrowly scoped to the exact problem at hand. I'm just pointing it out so it gets addressed in the likely future changes that happen to 10.5.

# felix (14 years ago)

On Sat, Jan 28, 2012 at 7:13 PM, Jeff Walden <jwalden+es at mit.edu> wrote:

At least, if you consider |with| and |eval| fun (and who doesn't?):

js> var x = "outer"; function f() { with({ x: 17 }) eval("var x"); return x; } typeof f()  "undefined"

This seems to be the behavior in every engine out there.  But according to the last ES5 errata for 10.5, and in the latest ES6 draft, since "x" has a binding in the object environment record created when executing the |with| statement's substatement, and the object supplied to the |with| isn't the global object, the |var x| should do nothing whatsoever.  Presumably given this implementation unanimity the spec should change on this point.

It seems to me the behavior you observe conforms to spec.

12.10, the with statement changes the Lexical Environment, but not the Variable Environment.

10.4.2, the eval is a direct eval, and it's not strict, so the Lexical Environment for the eval comes from the with, but the Variable Environment for the eval comes from the f function scope.

10.5 and 12.2, the var in the eval adds a binding for x in the current Variable Environment, which is the f function scope, but an assignment to x in the eval would modify the x in the Lexical Environment, which is the x established by the 'with'. 12.2 has a sentence noting this irregularity.

since the x created in f's Variable Environment by the eval is never assigned any value, the result returned from f is undefined.

# Jeff Walden (14 years ago)

On 01/28/2012 08:20 PM, felix wrote:

It seems to me the behavior you observe conforms to spec.

Hmm, yes, on second look I think you're right. I guess I was reading overfast and missed the variable environment/lexical environment distinction there. That, or it's been too long since I looked at this stuff. Probably both.

# Andreas Rossberg (14 years ago)

On 29 January 2012 04:13, Jeff Walden <jwalden+es at mit.edu> wrote:

At least, if you consider |with| and |eval| fun (and who doesn't?):

js> var x = "outer"; function f() { with({ x: 17 }) eval("var x"); return x; } typeof f()  "undefined"

This is really just an instance of JavaScript's, er, creative rules for var-hoisting. You need neither eval' norwith' to witness them, the same happens with

var x = "outer"; function f() { with({ x: 17 }) { var x } return x; } typeof f()

or

var x = "outer"; function f() { try { throw 17 } catch(x) { var x } return x; } typeof f()

That's why you will want to use `let' in the future. :)