javascriptscopehoistingjavascript-function-declaration

Why order of sloppy-mode function statement in block affects global variable differently?


snippet 1 -> output is "b"


if (true) {
  x = "b";
  function x() {}
}
console.log(x); //b

snippet 2 -> output is ƒ x() {}


if (true) {
  function x() {}
  x = "b";
}
console.log(x); // ƒ x() {}

I know that using strict mode will not affect the global variable at all, but I want to know how x is being assigned different values when strict mode is disabled.


Solution

  • See What are the precise semantics of block-level functions in ES6?: the function declares a local (block-scoped) variable, which the x = 'b' assignment will overwrite. However, it also exposes the value of that local variable at the point of the function declaration to the outer scope, creating the global variable that your console.log(x) after the block observes.

    Transforming the code to more explicit let declarations leads to

    // snippet 1
    if (true) {
      let _x = function x() {}; // hoisted
      _x = "b"; // assigns local _x
      x = _x; // where the `function` declaration was
    }
    console.log(x); // b
    

    and

    // snippet 2
    if (true) {
      let _x = function x() {}; // hoisted
      x = _x; // where the `function` declaration was
      _x = "b"; // assigns local _x
    }
    console.log(x); // ƒ x() {}