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
[email protected]
https://mail.mozilla.org/listinfo/es-discuss