17

Please consider the official ECMAScript specification as the source for your answer, and not a document published by a specific browser vendor. (I am aware of Mozilla extending its JavaScript implementation with "function statements".)

So, according to the ECMAScript spec, ergo, the syntactic productions defined in it, is this valid?

if (foo) {
    function x() { return; }
}

Update: My question can also be phrased like so: Can the Statement production contain the FunctionDeclaration production?

Conclusion: The answer is NO.

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385

7 Answers7

20

I do not agree with the other answers that say it is valid.

According to the ECMA-262 5th Edition specification, Blocks can only contain Statements (Section 12.1):

Block :
   { StatementList opt }

StatementList :
   Statement
   StatementList  Statement

However the spec does not define a function statement, but only a FunctionDeclaration and a FunctionExpression. The spec goes further to make a note on this in Section 12:

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 difference, 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.

For further reading, you may also be interested in checking out the comp.lang.javascript FAQ Section 4.2:

4.2 What is a function statement?

The term function statement has been widely and wrongly used to describe a FunctionDeclaration. This is misleading because in ECMAScript, a FunctionDeclaration is not a Statement; there are places in a program where a Statement is permitted but a FunctionDeclaration is not. To add to this confusion, some implementations, notably Mozillas', provide a syntax extension called function statement. This is allowed under section 16 of ECMA-262, Editions 3 and 5.

Example of nonstandard function statement:

// Nonstandard syntax, found in GMail source code. DO NOT USE.
try {
  // FunctionDeclaration not allowed in Block.
  function Fze(b,a){return b.unselectable=a}
  /*...*/
} catch(e) { _DumpException(e) }

Code that uses function statement has three known interpretations. Some implementations process Fze as a Statement, in order. Others, including JScript, evaluate Fze upon entering the execution context that it appears in. Yet others, notably DMDScript and default configuration of BESEN, throw a SyntaxError.

For consistent behavior across implementations, do not use function statement; use either FunctionExpression or FunctionDeclaration instead.

Example of FunctionExpression (valid):

var Fze;
try {
  Fze = function(b,a){return b.unselectable=a};
  /*...*/
} catch(e) { _DumpException(e) }

Example of FunctionDeclaration (valid):

// Program code
function aa(b,a){return b.unselectable=a}
Daniel Vassallo
  • 337,827
  • 72
  • 505
  • 443
  • Awesome answer, great reference to ECMAScript Spec – contactmatt Feb 26 '13 at 16:21
  • Amazing Answer, thanks for going into so much detail, I was struggling to find a decent answer! – RustyCollins Jan 29 '14 at 15:42
  • +1 I totally agree. You should not put function declarations within blocks, especially logic or flow blocks (if, while, switch, etc.) This is also a JSLint/JSHint rule. – CodeDreamer68 Jul 01 '15 at 20:39
  • 1
    Please see [*ECMAScript 2015 §13.2*](http://www.ecma-international.org/ecma-262/6.0/#sec-block) which explicitly allows declarations as a *StatementListItem*. Function declarations are allowed in blocks (and always have been). The only issue is that one browser decided to treat declarations in blocks as statements, which was permissible. – RobG May 18 '16 at 02:06
  • quite some time has passed since November 2010, the time this answer was posted at. I wonder if the specs have changed since then ? – doubleOrt Sep 15 '17 at 11:04
3

I'm not sure how to read this, but ECMA-262 V5 has this to say:

NOTE 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 difference, 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.

If I understand this correctly, strictly speaking, this means that function declarations can't be inside blocks at all, because Blocks can contain only Statements.

I can be totally wrong with my interpretation, though - I am not familiar with the internal workings of ECMAScript.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • Hallelujah, somebody understands the production rules – Šime Vidas Nov 01 '10 at 17:34
  • @Šime Thanks! As said, I'm not an expert here so take with a grain of salt. But what @casablanca says seems to confirm this – Pekka Nov 01 '10 at 17:39
  • 1
    "*this means that function declarations can't be inside blocks at all,*" no, it does not. What it means is that function declarations within blocks should not be treated as statements. – RobG May 18 '16 at 02:02
3

No, it's invalid. Function declarations can only appear as "source elements", which are either in the global scope or immediately within another function definition, outside all other statements. From the ECMA-262 spec:

FunctionBody : SourceElements

Program : SourceElements

SourceElement : Statement | FunctionDeclaration

There is no other production in the grammar that allows a FunctionDeclaration.

Only function expressions are allowed to be part of a statement:

MemberExpression : FunctionExpression

...

Statement : ExpressionStatement

Edit: There was a related discussion on another question recently. See the comments on this answer - earlier, I too thought that this could be valid but the grammar makes it clear that it is invalid.

Community
  • 1
  • 1
casablanca
  • 69,683
  • 7
  • 133
  • 150
2

From ECMA 262 chapter 14

  1. Program Syntax

Program : SourceElements SourceElements : SourceElement SourceElements SourceElement SourceElement : Statement FunctionDeclaration Semantics

The production Program : SourceElements is evaluated as follows:

  1. Process SourceElements for function declarations.

  2. Evaluate SourceElements.

  3. Return Result(2).

The production SourceElements : SourceElement is processed for function declarations as follows:

  1. Process SourceElement for function declarations.

The production SourceElements : SourceElement is evaluated as follows:

  1. Evaluate SourceElement.

  2. Return Result(1).

The production SourceElements : SourceElements SourceElement is processed for function declarations as follows:

  1. Process SourceElements for function declarations.

  2. Process SourceElement for function declarations.

The production SourceElements : SourceElements SourceElement is evaluated as follows:

  1. Evaluate SourceElements.

  2. If Result(1) is an abrupt completion, return Result(1)

  3. Evaluate SourceElement.

  4. Return Result(3).

The production SourceElement : *Statement is processed for function* declarations by taking no action.

The production SourceElement : *Statement is evaluated as follows:*

1. Evaluate Statement.

2. Return Result(1).

The production SourceElement : FunctionDeclaration is processed for function declarations as follows:

  1. Process FunctionDeclaration for function declarations (see clause 13).

The production SourceElement : FunctionDeclaration is evaluated as follows:

  1. Return (normal, empty, empty).

The awnser is officially NO. (Šime Vidas convinced me the hard way in another question)

But no Exception is specified either so it fails or works silently depending on browser implementations.

BGerrissen
  • 21,250
  • 3
  • 39
  • 40
1

Version 5 of ECMA-262 says it shouldn't be valid:

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 within Block is when it is part of ExpressionStatement. However, ExpressionStatement is explicitly defined to not begin with "function" keyword, and this is exactly what makes FunctionExpression invalid as part of a Statement or Block (note that Block is merely a list of Statements).

However, it seems not many interpreters obey this rule. Kangax says they should be considered syntactical errors per this page:

Because of these restrictions, whenever function appears in a block (such as in 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.

meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
0

In the ECMAScript standard, a FunctionDeclaration is not defined as a Statement, and a Statement is not defined as being able to contain a FunctionDeclaration, so they are not compatible according to the standard (though in practice every JavaScript interpreter will attempt to do something sensible, albeit not consistent between implementations).

Chuck
  • 234,037
  • 30
  • 302
  • 389
-1

Yes it is valid.

All statement blocks (i.e everything within curly braces) can have additional statements and declarations, including functions.

So you can also define functions within functions and so on

Here is ECMA-262 v1 - http://www.mozilla.org/js/language/E262.pdf

Simon
  • 37,815
  • 2
  • 34
  • 27
  • A block may contain a list of zero or more statements. But function declarations are not statements. – Šime Vidas Nov 01 '10 at 17:34
  • You're correct, function declarations are permissible in blocks. The problem is that one browser treats them as a statement. – RobG May 18 '16 at 02:00
  • @RobG which browser? – doubleOrt Sep 15 '17 at 10:58
  • 1
    @Taurus—actually more than one: in Firefox, Chrome and Opera `if (false) function foo(){console.log('foo')}; foo()` throws a type error: foo is not a function. *foo* is created as a variable due to the expression being treated like a function declaration, but a value isn't assigned due to it being in a conditional block that is not executed (due to `if (false)`), so it's being treated as a statement. In Safari, it shows "foo", so it's being treated as a function declaration and the assignment isn't conditional. – RobG Sep 18 '17 at 02:32
  • @RobG +1. However, were you talking about Firefox in your first comment ? I am asking because many articles I have read say that only Firefox treats them as a statement (I think even the ECMA specs said this), are those articles simply outdated ? – doubleOrt Sep 18 '17 at 21:01
  • Yes. Firefox did it first, then ECMAScript ed 5 came out and covered it in an appendix as an extension with the rider that basically says "please don't do this". It required the spec to jump through a few hoops in order to be backward compatible (i.e. old code will run the same in an ES5 environment). – RobG Sep 19 '17 at 06:49