Skip to content

Instantly share code, notes, and snippets.

@ajklein
Last active November 28, 2017 22:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ajklein/b947351835cc77ad0040db9a55813f51 to your computer and use it in GitHub Desktop.
Save ajklein/b947351835cc77ad0040db9a55813f51 to your computer and use it in GitHub Desktop.
Parameter scoping and sloppy eval
// What does this code do?
function f(x = eval("var z = 2; 1"), y = z) {
return [x, y, z];
}
f();
// Spec says to throw a ReferenceError, since 'z' is not visible either
// to other parameters in the list, or to the function body.
//
// Results in various engines:
//
// V8, SpiderMonkey, recent Chakra: ReferenceError: z is not defined
// Chakra (until recently): (early) SyntaxError: 'eval' is not allowed in the default initializer
// JavaScriptCore: returns [1, 2, 2]
// What about this?
function g(x = eval("var z = 2; 1"), y = z) {
var z;
return [x, y, z];
}
g();
// Spec, SM, V8: ReferenceError: z is not defined
// JSC: returns [1, 2, undefined]
// Proposal: switch the spec to the JavaScriptCore behavior.
@littledan
Copy link

What do you think this should do?

@ajklein
Copy link
Author

ajklein commented Nov 27, 2017

@littledan I can't think of a reason that JSC's behavior is particularly bad, and it seems a lot easier to implement than what V8, SpiderMonkey, and the spec do today.

@syg
Copy link

syg commented Nov 28, 2017

@ajklein I agree the current semantics is very odd and a pain to implement. Let's be specific: is the proposal that sloppy eval var bindings be allowed to escape to other parameter expression, or also the function body? I oppose letting dynamic var bindings escape to function body, which isn't going to make implementation any easier.

Yet another fix that is both simple to reason about and implement IMO is make all evals in parameter expression positions strict, regardless of the enclosing script's strictness. The current semantics is super weird in that bindings are allowed to escape the eval, but not the parameter expression position. This means you can access z in your example with a comma expression after eval.

@ajklein
Copy link
Author

ajklein commented Nov 28, 2017

@syg JSC apparently creates the var binding in the parameter scope, as adding a "var z;" to the function body causes the return value to be [1, 2, undefined]. I think that's the semantics I'd want.

@syg
Copy link

syg commented Nov 28, 2017

@ajklein I still prefer all eval being strict, thus no ability to make new var bindings at all in parameter expressions. I think that aligns closer with the intent of the current semantics. Is there a V8 implementation preference against that? Seems simplest of all possible semantics to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment