Why doesn't function declaration as body of If statement result in an error in JavaScript?
Asked Answered
R

2

7

In the MDN documentation for "Statements and declarations" it is mentioned:

The terms "statement" and "declaration" have a precise meaning in the formal syntax of JavaScript that affects where they may be placed in code. For example, in most control-flow structures, the body only accepts statements — such as the two arms of an if...else. If you use a declaration instead of a statement, it would be a SyntaxError. For example, a let declaration is not a statement, so you can't use it in its bare form as the body of an if statement.

The following code will give an error:

if(true) 
  let x = 0;

Now functions declarations are also just declarations right? Then why doesn't the following code give the same error?

if(true)
function foo() {}
Remonstrant answered 19/9, 2023 at 6:18 Comment(8)
They're a different type of declaration. stackoverflow.com/a/20140626Hokusai
Because it is used in the context of an expression, that is not a function declaration but a (named) function expression.Crore
@Crore I was thinking that too, but isn't the name of the named function expression only available within the body of the function itself, and not outside of it, ie: +function bar() {}; bar(); gives an error saying that bar is not defined. If function foo() {} is being treated as a function expression, then I would think that trying to execute it after would fail, but instead it works. My guess is that it has something to do with the web-compatibility part of the spec.Horaciohorae
I think the difference is that function declarations (and yes, that's what that is; it's not a function instantiation expression because the function keyword appears at token #1 of a statement context) are scoped to the function in which they appear. Without a "declarative environment record" after the if, the let declaration is near nonsense. If it were allowed, it would be useless except for side-effects of the initialization expression. The lack of any place to "put" the declared symbol is probably more significant.Dulcy
That's speculation on my part. Both of those code examples represent bad code; if the function declaration were considered an error I would not mind at all.Dulcy
Label statements says There is a legacy grammar that allows function declarations to be labeled in non-strict code. I believe it's the same thing here. In strict mode, the second code fails as well.Hokusai
@Hokusai Funniest syntax error I've ever seen: SyntaxError: In strict mode code, functions can only be declared at top level or inside a block. I would have thought that either top level or inside a block would cover 100% of cases but it looks like I overlooked this possibility.Noel
Strongly related: function declarations cannot be inside an if statement according to ecmascriptRetriever
Q
2

Edition 5.1 has a note specifically addressing this problem:

Several widely used implementations of ECMAScript are known to support the use of FunctionDeclaration as a Statement. However there are significant and irreconcilable variations among the implementations in the semantics applied to such FunctionDeclarations. Because of these irreconcilable differences, the use of a FunctionDeclaration as a Statement results in code that is not reliably portable among implementations. It is recommended that ECMAScript implementations either disallow this usage of FunctionDeclaration or issue a warning when such a usage is encountered. Future editions of ECMAScript may define alternative portable means for declaring functions in a Statement context.

From the next edition through the current one, the second construct is covered by an additional feature specified in Annex B, which is required when the host is a web browser:

IfStatement[Yield, Await, Return]:

   if ( Expression[+In, ?Yield, ?Await] ) FunctionDeclaration[?Yield, ?Await, ~Default]

Quadrillion answered 19/9, 2023 at 11:13 Comment(0)
N
-4

Because declaring a function using the function keyword puts it in the global scope.

Make a simple test:

if (true) {
   function foo(x) { return x+2 }
}
console.log(foo(5))

Will result in '7' in the console, proving that the function was actually defined outside the if.

On the opposite the variable explicitly defined inside the if will be scoped to the if.

Note this code will raise an error because bar will not be defined outside the if.

if (true) {
    const bar = function (x) { return x+2 }
}
console.log(bar(5))
Nabataean answered 19/9, 2023 at 8:56 Comment(2)
That's not what the question is about.Quadrillion
"declaring a function using the function keyword puts it in the global scope" - that's totally wrongRetriever

© 2022 - 2025 — McMap. All rights reserved.