On Feb 14, 2014, at 5:49 AM, André Bargull wrote: >> >> How about this? >> >> let x= 0; >> if (1) eval("let x= 42; alert(x);"); //Is this in its own block? >> alert(x); > > `eval()` hasn't yet been updated to work with the new lexical declaration > forms, but I hope the example from above will be evaluated in a new block. > See https://bugs.ecmascript.org/show_bug.cgi?id=1788 for a related bug report.
Goood point and this is something I need to specify in the next couple weeks so let's look at the alternatives. First a quick refresher on ES5 era eval. In ES5, the binding behavior of direct eval differs between strict and non-strict modes. In strict mode, each eval instantiates all declarations in a new environment that is immediately nested within the current LexicalEnvironment. The scoping behavior is essentially the same as if the eval code was the body of an iife that occurred at the same place as the eval call. Bindings introduced by the eval code disappear after completion of the eval. In non-strict mode, each eval instantiates all declarations in the current VariableEnvironment; that is the most immediately enclosing function or global environment. Bindings introduced by the eval code remain accessible from that VariableEnvironment after completion of the eval. For example: (function() { "use strict"; eval("var answer=42"); console.log(answer); // ReferenceError: answer is not defined })(); (function() { eval("var answer=42"); console.log(answer); // 42 })(); For ES6, it makes sense for strict mode evals to behave in this exact same way. Each eval takes place in its own environment and no bindings survive the completion of the eval. For ES6, non-strict evals of code containing only var or function declarations must have exactly the ES5 behavior in order to maintain compatibility. But what about eval code that contains new declaration forms (let/const/class) exclusively or in combination with var/function declarations? Three possibilities come to mind: 1) Extend the ES5 semantics to include the new declaration forms. For example: (function() { eval("let answer=42"); console.log(answer); // 42 })(); 2) Use the strict mode binding semantics if the eval code directly contains any of the new declaration forms: (function() { eval(" var answer=42; let forceSeprateEnvironment = true; "); console.log(answer); // ReferenceError: answer is not defined })(); 3) Combination. use ES5 non-strict binding semantics for var/function declarations but place let/const/class bindings into a per eval environment: (function() { eval(" var answer=42; let localToEval = true; "); console.log(answer); // 42 console.log(localToEval); // ReferenceError: localToEval is not defined )(); It would certainly be possible to specify #1, but I don't like it. Other than for the global environment it would be cleaner if the new block scope-able declarations were never dynamically added to the environment. I think either #2 or #3 is plausible. #2 is a simpler story but introduces a refactoring hazard. If you have some existing eval code that defines some "global" functions or variables, then simply adding a let/const/class declaration to the eval code ruins those global declarations. I prefer the simplicity of #2, but I also worry about the WTF impact it might have on evolving existing code. Can we get away with #2, or are we going to have to go with #3? Are there other alternatives? Allen
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss