He estado mirando ecma262 y he visto que cuando invocamos una función básicamente estamos llamando al método interno [[Call]] y mientras miraba los pasos de [[Call]] he encontrado que en el paso 2 llama a PrepareForOrdinaryCall y aquí está la parte interesante.
- Sea localEnv NewFunctionEnvironment(F, newTarget).
- Establezca LexicalEnvironment de calleeContext en localEnv.
- Establezca VariableEnvironment de calleeContext en localEnv.
PrepareForOrdinaryCall establece el LE y el VE en localEnv que es un FunctionEnvironmentRecord recién creado.
Por lo tanto, LE y VE apuntan a la misma ER.
Echa un vistazo al siguiente código:
function test(){ let localVar = 5; var myVar = 10; } test();let localVar va a ser parte del FunctionEnvironmentRecord al que LE y VE están apuntando actualmente o va a crear un nuevo ER y establecer el LE en él y dentro del nuevo ER al que apunta LE va a almacenar let localVarAquí algunas imágenes para demostrarlo visualmente.
Ejemplo 1
es let localVar va a ser parte del FunctionEnvironmentRecord al que apuntan actualmente LE y VE
Ejemplo 2
o va a crear una nueva ER y establecer el LE en ella y dentro de la nueva ER que apunta LE va a almacenar let localVar
¿Cuál de esos ejemplos es el correcto?
PrepareForOrdinaryCallestablece el LE y el VE en localEnv, que es un FunctionEnvironmentRecord recién creado.Por lo tanto, LE y VE apuntan a la misma ER.
Sí. Sin embargo, en ese paso, no se han creado variables.
¿Va a ser
let localVarparte del FunctionEnvironmentRecord al que apuntan actualmente LE y VE, o va a crear un nuevo ER y establecer el LE en él y dentro del nuevo ER almacenar ellocalVar?
No te gustará la respuesta, pero depende :-)
Los pasos interesantes que van a crear estas variables no ocurren en PrepareForOrdinaryCall sino en FunctionDeclarationInstantiation . En la mayoría de las funciones ordinarias, sí, se aplica el escenario simple 1 donde ambas variables se crean en el mismo registro de entorno. (Sin embargo, señalaría que su imagen se ve como si hubiera dos registros de entorno separados que contenían las dos variables, querrá dibujar un diagrama de objetos con un solo objeto de registro de entorno al que se hace referencia como el entorno variable y léxico ).
Sin embargo, en funciones que tienen inicializadores de parámetros predeterminados, o funciones que no son código de modo estricto, se crearán registros de entorno declarativos adicionales y el LexicalEnvironment del contexto de ejecución se establecerá en ellos. En particular,
" Paso 20: NOTA: Se necesita un Registro de entorno separado para garantizar que los enlaces creados por llamadas de evaluación directa en la lista de parámetros formales estén fuera del entorno donde se declaran los parámetros. "
" Paso 28: NOTA: Se necesita un Registro de entorno separado para garantizar que los cierres creados por expresiones en la lista de parámetros formales no tengan visibilidad de las declaraciones en el cuerpo de la función. "
" Paso 30 - NOTA: Las funciones no estrictas usan un Registro de entorno separado para las declaraciones léxicas de nivel superior, de modo que una evaluación directa pueda determinar si alguna declaración de ámbito var introducida por el código de evaluación entra en conflicto con las declaraciones de ámbito léxico de nivel superior preexistentes. Esto no es necesario para funciones estrictas porque una evaluación directa estricta siempre coloca todas las declaraciones en un nuevo Registro de entorno.
Con la ejecución de estos pasos, el contexto de ejecución de test() se parecerá más a su segundo escenario. (Aunque al registro de entorno declarativo en su imagen le falta de manera crucial la referencia [[OuterEnv]] )
También puede usar un alcance de bloque para crear esta configuración explícitamente:
function test(){ var myVar = 10; { let localVar = 5; debugger; } } test();