Is a function hoisted if it is defined within an if condition?
Asked Answered
D

3

7

So suppose I have something like this

var x = 1;
   if (function f(){}) {
     x += typeof f;
   }
   x;

This outputs "1undefined". I thought it should have output "1function", because function f(){} should have been hoisted above the if. This is clearly not the case - why? I thought function declarations and bodies were always hoisted to the top of the scope?

Delate answered 27/7, 2015 at 21:57 Comment(3)
Actually, it is, see: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Premer
I think this is a named function expression, not a function declaration. The scope of the name is just the body of the function being defined, not the surrounding function.Unchancy
It's like var foo = function f() {};.Unchancy
U
8

Function declarations are hoisted. Function expressions are not.

This creates a named function expression:

if(function f(){})

It doesn't do anything except check to see if the function expression is truthy. (Function expressions are always truthy.)

Regarding named function expressions, see https://kangax.github.io/nfe/#named-expr:

An important detail to remember is that this name is only available in the scope of a newly-defined function

This code is outside the scope of the new function expression, and therefore f is undefined:

x += typeof f;

Within a named function expression, you can refer to its name without a problem:

(function f() {
  alert(typeof f);   //function
})();

alert(typeof f);     //undefined
Uball answered 27/7, 2015 at 22:53 Comment(2)
I don't think toString is relevant. Functions are object types and are converted to true in boolean contexts.Seat
One key thing to understand here is that function f(){} by itself is a function declaration (which would have been hoisted). But surrounding it with parentheses makes it a function expression (which is not hoisted), since that grouping operator (the parentheses) can only contain an expression.Corundum
K
4

As far as I know ES5 does not define the behavior for function declarations inside blocks.

Quoting Kangax:

FunctionDeclarations are only allowed to appear in Program or FunctionBody. Syntactically, they can not appear in Block ({ ... }) — such as that of if, while or for statements. This is because Blocks can only contain Statements, not SourceElements, which FunctionDeclaration is. If we look at production rules carefully, we can see that the only way Expression is allowed directly within Block is when it is part of ExpressionStatement. However, ExpressionStatement is explicitly defined to not begin with "function" keyword, and this is exactly why FunctionDeclaration cannot appear directly within a Statement or Block (note that Block is merely a list of Statements).

Because of these restrictions, whenever function appears directly in a block (such as in the previous example) it should actually be considered a syntax error, not function declaration or expression. The problem is that almost none of the implementations I've seen parse these functions strictly per rules (exceptions are BESEN and DMDScript). They interpret them in proprietary ways instead.

Kozhikode answered 27/7, 2015 at 22:4 Comment(6)
Does Block really refer to the if ( ) part or the { body } part after it?Unchancy
I'm almost sure that the if ( ) itself is considered a block too... but not 100% :(Kozhikode
since you can declare a variable inside a for ( ) and its only valid inside its block... I guess it works the same wayKozhikode
so..why would the above produced 1undefined? (weirdly, I took the example from perfectionkills.com/whats-wrong-with-extending-the-dom, which is something kangax wrote)Delate
If you look at the code before the quote, it looks like I was write. He's talking about if (foo) { function bar() {...} }Unchancy
Yeah, the function in the OP's code is not in a block, which is defined as { StatementList }.Seat
S
0

Function declarations are statements. The conditional part of an if-statement is an expression, so what you have is a function expression; it cannot be a function declaration. And so it isn't hoisted, since only function declarations are.

Seat answered 28/7, 2015 at 0:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.