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 declare functions inside blocks and don't rely on this code to behave in this way.
This is also explained here