-
-
Save bakkot/60121065ef615c26f8bdf42839e310df to your computer and use it in GitHub Desktop.
var p = () => console.log(f); | |
{ | |
p(); // undefined | |
console.log(f); // function f(){} | |
f = 1; | |
p(); // undefined | |
console.log(f); // 1 | |
function f(){} | |
p(); // 1 | |
console.log(f); // 1 | |
f = 2; | |
p(); // 1 | |
console.log(f); // 2 | |
} |
@kstratis, the spec has the full details.
The summary is:
In sloppy mode, block-scoped function declarations (usually) create two bindings: one scoped to the block, and one scoped to the function or script containing it. That is, function f(){}
in a block is also secretlyvar f
. The function is hosted to the top of the block, like usual, but then when the declaration is executed it has the effect of reading from the block-scoped binding and copying its value to the var-scoped binding.
In other words, the code above is a lot like the below, except that f2
below is also named f
.
var f2; // note this new thing!
var p = () => console.log(f2);
{
function f(){} // hoisted!
p();
console.log(f);
f = 1;
p();
console.log(f);
f2 = f; // the function declaration, when executed, has the effect of reading from the lexical binding and writing to the var binding.
p();
console.log(f);
f = 2;
p();
console.log(f);
}
I should mention that this is just a compatibility hack in the specification, since block-scoped function declarations were not previously a part of the ECMAScript spec but were commonly supported with inconsistent semantics in browsers. These semantics are only intended to capture behavior which would have worked across browsers, to avoid breaking things which previously worked everywhere; it's not intended to be sensible.
Don't write sloppy-mode code and you won't need to worry about it.
Could you please provide some further explanation on this one?
I totally tripped on line 8...