Skip to content

Instantly share code, notes, and snippets.

@bakkot
Created November 29, 2016 21:28
Show Gist options
  • Save bakkot/60121065ef615c26f8bdf42839e310df to your computer and use it in GitHub Desktop.
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
Copy link

kstratis commented Nov 30, 2016

Could you please provide some further explanation on this one?
I totally tripped on line 8...

@bakkot
Copy link
Author

bakkot commented Dec 15, 2016

@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);
}

@bakkot
Copy link
Author

bakkot commented Dec 15, 2016

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment