-1

I thought all functions and their bodies got hoisted. I did this test:

foo();
var blah = true;
if (!blah) function foo() { console.log('falsy') }
else function foo() { console.log('truthy') }

And I get that foo is not a function. It seems its making foo a variable and its declaration got hoisted. But it doesn't get initialized till the if statement.

I was surprised by two things:

  1. The last function foo didn't get its body hoisted
  2. I didn't see ReferenceError: foo is not defined but instead i saw TypeError: foo is not a function
halfer
  • 19,824
  • 17
  • 99
  • 186
Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • 3
    Well one problem is that the definition of `foo()` is ambiguous at the top of the block. Both functions have the same name, so if both are hoisted there'll only be one. But that conflicts with the apparent semantics of the `if` statement. Really nested function declaration statements are a syntax wart and are disallowed for good reason in "strict" mode. – Pointy Jan 15 '19 at 23:11
  • 1
    Check out this answer: https://stackoverflow.com/a/10069457/1882497 – Aioros Jan 15 '19 at 23:13
  • 2
    Possible duplicate of [Function declarations inside if/else statements?](https://stackoverflow.com/questions/10069204/function-declarations-inside-if-else-statements) – ggorlen Jan 15 '19 at 23:18

2 Answers2

1

Functions have scope to their current block and they are hoisted to the top of their current block, you have two blocks in that if statement

  if (!blah) {
    function foo() { console.log('falsy') }
  } else {
    function foo() { console.log('truthy') }
  }

If you format it like that you will see the two foos and their scope is within the brackets.

Just like how hello below fails as it only has scope to the block in which it is defined.

hello();
{
  function hello() {
    console.log('hello');
  }
}
Adrian Brand
  • 20,384
  • 4
  • 39
  • 60
  • If it was hoisted only to top of current block, as I was expecting, then calling `foo()` outside of the block, before the block, should give `ReferenceError: foo is not defined`, right? – Noitidart Jan 16 '19 at 11:16
  • 1
    Hit the run code snippet button above for the error you get with the hello function. – Adrian Brand Jan 17 '19 at 01:13
1

First - you're calling function foo before it is actually defined. The value of blah is not defined yet there. But it is in the global scope already if that's what you meant by body hoisted.

Second - the foo actually is defined, because all var and function declarations get defined before the execution, on a preprocessing stage. So on the line with foo(), foo is defined but not initialized, because it gets initialized under condition which is yet about to be processed.

Also, what you're trying to do is a bad practice, it will cause an error on preprocessing with "use strict"; declaration on top

Blue
  • 355
  • 1
  • 9
  • Calling a function before it is defined is allowed as they are hoisted to the top of the block they are defined in, that is what OP's question is about. – Adrian Brand Jan 16 '19 at 02:57
  • 1
    not if definition is conditional, it causes undefined behavior, in new standard it's even forbidden. That's what I'm truing to explain – Blue Jan 16 '19 at 03:02