2

I have been looking at ecma262 and I've seen that when we invoke a function we are basically calling the internal method [[Call]] and while I was looking at the steps of the [[Call]] I have found that in step 2 it calls to PrepareForOrdinaryCall and here is the interesting part.

  1. Let localEnv be NewFunctionEnvironment(F, newTarget).
  2. Set the LexicalEnvironment of calleeContext to localEnv.
  3. Set the VariableEnvironment of calleeContext to localEnv.

PrepareForOrdinaryCall sets the LE and the VE to localEnv which is a newly created FunctionEnvironmentRecord.

Therefore, the LE and VE are pointing to the same ER.

Take a look at the following code:

function test(){
  let localVar = 5;
  var myVar = 10;
}

test();
My question is the let localVar is going to be part of the FunctionEnvironmentRecord which LE and VE are currently pointing to or it's going to create a new ER and set the LE to it and inside the new ER that LE pointing to it's going to store let localVar

Here some images to demonstrate it visually.

Example 1

is the let localVar is going to be part of the FunctionEnvironmentRecord which LE and VE are currently pointing to

enter image description here


Example 2

or it's going to create a new ER and set the LE to it and inside the new ER that LE pointing to it's going to store let localVar

enter image description here

Which one of those examples is the correct one?

phentnil
  • 2,195
  • 2
  • 14
  • 22
AngryJohn
  • 576
  • 4
  • 10

1 Answers1

3

PrepareForOrdinaryCall sets the LE and the VE to localEnv which is a newly created FunctionEnvironmentRecord.

Therefore the LE and VE are pointing to the same ER.

Yes. However at that step, no variables have been created.

Is the let localVar going to be part of the FunctionEnvironmentRecord which LE and VE are currently pointing to, or is it going to create a new ER and set the LE to it and inside the new ER store the localVar?

You won't like the answer, but it depends :-)

The interesting steps that are going to create these variables are not happening in PrepareForOrdinaryCall but in FunctionDeclarationInstantiation. In most ordinary functions, yes, the simple scenario 1 applies where both variables are created in the same environment record. (I would however point out that your image looks as if there were two separate environment records that both contained the two variables, you'll want to draw an object diagram with a single environment record object that is referenced as both the variable and lexical environment).

However, in functions that have default parameter initialisers, or functions that are not strict mode code, additional declarative environment records will be created and the execution context's LexicalEnvironment will be set to those. In particular,

"Step 20 - NOTE: A separate Environment Record is needed to ensure that bindings created by direct eval calls in the formal parameter list are outside the environment where parameters are declared."

"Step 28 - NOTE: A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body."

"Step 30 - NOTE: Non-strict functions use a separate Environment Record for top-level lexical declarations so that a direct eval can determine whether any var scoped declarations introduced by the eval code conflict with pre-existing top-level lexically scoped declarations. This is not needed for strict functions because a strict direct eval always places all declarations into a new Environment Record."

With these steps being executed, the execution context of test() will look more like in your second scenario. (Although the declarative environment record in your image is crucially missing the [[OuterEnv]] reference)

You can also use a block scope to create this setup explictly:

function test(){
  var myVar = 10;
  {
    let localVar = 5;
    debugger;
  }
}
test();
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Amazing answer. can i speak to you in a chat it seems like you're the guy when it comes to the ecmascript spec i just wanted to ask couple questions if that's ok – AngryJohn Oct 02 '21 at 22:28
  • Please [ask them as questions](https://stackoverflow.com/questions/ask) so that others can benefit from the answers as well :-) You can send me a link in a comment, I'll look at them tomorrow. – Bergi Oct 02 '21 at 22:33
  • Here some unfamiliar concept which i find hard to understand https://stackoverflow.com/questions/69424594/what-is-realm-and-why-do-we-need-itecma262 – AngryJohn Oct 03 '21 at 11:54
  • so that's mean that if the function isn't using 'use strict' it will create a new ER and point LE to it. but what if i dont have any let and const declarations inside the function body so it will just create an empty ER and will point LE to it ? – AngryJohn Oct 06 '21 at 14:51
  • @AngryJohn Yes, it might - though of course lexical environments are subject to optimisation. Just because the specification of how they must work describes them as nested, doesn't mean they are actually implemented like that. – Bergi Oct 06 '21 at 20:48