The note below the PerformEval abstract operation says:
The eval code cannot instantiate variable or function bindings in the variable environment of the calling context that invoked the eval if the calling context is evaluating formal parameter initializers or if either the code of the calling context or the eval code is strict mode code. Instead such bindings are instantiated in a new VariableEnvironment that is only accessible to the eval code. Bindings introduced by let, const, or class declarations are always instantiated in a new LexicalEnvironment.
Question:
What is meant by "if the calling context is evaluating formal parameter initializers"? What is a "parameter initializer"?
There is only one other reference to the term "parameter initializer" in the spec in Note 3 of 9.2.10. This note says:
Parameter Initializers may contain direct eval expressions. Any top level declarations of such evals are only visible to the eval code (10.2). The creation of the environment for such declarations is described in 14.1.22.
I interpreted this as meaning that if a parameter initializer expression contains an eval call, then any variables created inside that eval call are not instantiated in the parameter scope. So, in the example below, I was expecting a ReferenceError
to be thrown since c
shouldn't be instantiated in the parameter scope:
function t(a = eval('var c = 8'), b = () => c) {
console.log(b())
}
t() // 8
But as you can see from the console output, my interpretation isn't correct. Even though c
was created inside an eval call, its value is still visible to the funarg defined by b
and can thus be printed to the console.
Turns out you found a specification bug! I asked in TC39's Matrix chat and they've created a PR to remove this note:
https://github.com/tc39/ecma262/pull/2428
The behavior in the note used to be correct, but was removed in 2017 in https://github.com/tc39/ecma262/pull/1046