20

var a;
if (true) {
  a = 5;

  function a() {}
  a = 0;
  console.log(a)
}
console.log(a)

I saw the code above, a function is declared in {}. I think it would print 0 0, but it prints 0 5

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Marcus Lee
  • 425
  • 2
  • 7
  • 1
    Does this answer your question? [What are the precise semantics of block-level functions in ES6?](https://stackoverflow.com/questions/31419897/what-are-the-precise-semantics-of-block-level-functions-in-es6) – Jonas Wilms Oct 30 '19 at 06:52
  • 2
    In strict mode, it logs `0 undefined`. – CertainPerformance Oct 30 '19 at 06:54
  • @certainPerformance well, that's explainable, but I fail to explain that `a = 5` leaves the block. According to bergi in the dupe, `function a` will be hoisted. – Jonas Wilms Oct 30 '19 at 06:57
  • 2
    Seems as if the locally scoped block variable gets copied to the outer block when reaching the function declaration. – Jonas Wilms Oct 30 '19 at 07:16

1 Answers1

18

The following happens:

(1) There exist two variable declarations a, one inside the block and one outside of it.

(2) The function declaration gets hoisted, and bound to the inner blocks variable.

(3) a = 5 is reached, which overrides the block variable.

(4) the function declaration is reached, and the block variable is copied to the outer variable. Both are 5 now.

(5) a = 0 is reached, which overrides the block variable. The outer variable is not affected by this.

 var a¹;
 if (true) {
   function a²() {} // hoisted
   a² = 5;
   a¹ = a²; // at the location of the declaration, the variable leaves the block      
   a² = 0;
  console.log(a²)
}
console.log(a¹);

This is actually not really part of the specification, it is part of the web legacy compatibility semantics, so don't rely on this code to behave in this way and always "use strict"; mode.

This is also explained here.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • But why once the function declaration is reached, the block variable will be copied to the outer variable?Concluded that from debugger? – Chor Oct 30 '19 at 12:30
  • @Chor no, the spec says so. I have no idea why. – Jonas Wilms Oct 30 '19 at 12:30
  • @Chor Because this is the way old browsers behaved with "conditional declaration statements", see e.g. https://kangax.github.io/nfe/#function-statements – Bergi Oct 29 '21 at 15:55