me han hecho una pregunta
{ function foo() { console.log('A'); } foo(); foo = 1; function foo() { console.log('B'); } foo = 2; console.log(foo); } console.log(foo); ¿Por qué la tercera salida es 1 en lugar de 2 ?
No debe crearse foo con alcance de bloque, ya que no hay ni let ni const en ese bloque. Pero la segunda salida de foo es 2 significa que, de hecho, se ha creado otra referencia de foo .
Que esta pasando?
PD: estoy usando la
Version 89.0.4389.90 (Official Build) (x86_64).
De acuerdo con la semántica de compatibilidad web en el lugar de la declaración de la función, el valor de la variable de ámbito bloqueado está vinculado al ámbito externo². Este código es equivalente a:
let outerFoo; // the functions create a binding outside of the scope { let innerFoo; // but also inside // due to hoisting, functions get bound before any code get's executed: innerFoo = function foo() { console.log('A'); }; innerFoo = function foo() { console.log('B'); }; // At the place of the function declaration, the variable leaves the scope /* function foo() { console.log('A'); } */ outerFoo = innerFoo; innerFoo(); innerFoo = 1; // this also applies to the second declaration /* function foo() { console.log('B'); } */ outerFoo = innerFoo; innerFoo = 2; console.log(innerFoo); } console.log(outerFoo);²Así es básicamente como lo describe la especificación:
When the FunctionDeclaration f is evaluated, perform the following steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6: a. Let fenv be the running execution context's VariableEnvironment. b. Let benv be the running execution context's LexicalEnvironment. c. Let fobj be ! benv.GetBindingValue(F, false). d. Perform ! fenv.SetMutableBinding(F, fobj, false).
La especificación establece además:
Antes de ECMAScript 2015, la especificación de ECMAScript no definía la ocurrencia de una declaración de función como un elemento de la lista de declaraciones de una declaración de bloque. Sin embargo, el soporte para esa forma de FunctionDeclaration era una extensión permitida y la mayoría de las implementaciones de ECMAScript alojadas en el navegador lo permitían. Desafortunadamente, la semántica de tales declaraciones difiere entre esas implementaciones. Debido a estas diferencias semánticas, el código ECMAScript web existente que usa declaraciones de función de nivel de bloque solo es portátil entre implementaciones de navegador si el uso solo depende de la intersección semántica de todas las implementaciones de navegador para tales declaraciones.
Por lo tanto, es probable que Safari lo esté haciendo como siempre lo hizo, mientras que Chrome (y Firefox) siguen la especificación.