1

Under ECMAScript's syntactic grammar for function declarations, we have the Runtime Semantics: Evaluation of function declarations.

It states that a FunctionDeclaration does not return anything (i.e. empty), and does not run any other code. Specifically, no new Declarative Environment Record (DER) is created, no function object is created, and no binding of an identifier to that function object occurs in the DER.

A FunctionExpression, on the other hand, runs InstantiateOrdinaryFunctionExpression, which does the above (binding only happens if it's a named function expression).

If I write function foo() {} it seems to me that it will be interpreted as a FunctionDeclaration, and thus no binding will be made on any environment record. Which means, when I call the function foo() I get a ReferenceError (Source)

What am I missing?

Magnus
  • 6,791
  • 8
  • 53
  • 84

1 Answers1

2

Function declarations do declare the function for the whole scope. The function objects are created and the bindings are created and initialised when the scope is set up in FunctionDeclarationInstantiation for function scopes, BlockDeclarationInstantiation for block scopes, InitializeEnvironment for module scopes, GlobalDeclarationInstantiation for global scopes etc.

When the statement is evaluated, it does indeed nothing1.

1: in strict mode, at least. In sloppy mode, there are some legacy semantics for block-scoped function declarations.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you, Bergi. I was thinking you would be the one to answer. The piece of the puzzle I am missing is where in the syntactic grammar we can see that `FunctionDeclarationInstantiation` is called. I searched for it in the spec, but it seems that function is only called when function bodies are evaluated: 15.2.3 Runtime Semantics: EvaluateFunctionBody (etc.). In other words, I want to follow the s. grammar and see that the instantiation happens. As noted in the OP, I can follow the grammar and see it for *FunctionExpression*, but not for *FunctionDeclaration*. – Magnus Dec 11 '22 at 12:46
  • 1
    "*It seems that `FunctionDeclarationInstantiation` is only called when function bodies are evaluated*" - yes, it is: that's when the declared variables are created in the function scope! They're **hoisted**. – Bergi Dec 11 '22 at 14:33
  • Indeed, I see in the grammar how the instantiation happens if a *FunctionDeclaration* appears inside a *FunctionBody* (i.e. in the *Function Execution Context*). However, a *FunctionDeclaration* might appear outside of a *FunctionBody*, for instance in the *Global Execution Context*. Do you know where in the grammar (in which Evaluation) the instantiation then begins? – Magnus Dec 11 '22 at 14:56
  • @Magnus it's in `GlobalDeclarationInstantiation` then, as linked in my answer. (I think the only case I didn't link are `eval` scopes) – Bergi Dec 11 '22 at 15:12
  • Ah, fantastic, it all came together now. Thank you! Just a quick algo question re. *GlobalDeclarationInstantiation*: There seems to be an overlap between *VarScopedDeclarations* and *LexicallyScopedDeclarations* (eg *FunctionDeclaration* is in both). Yet, it still creates bindings on the `Global Environment Record` for both (steps 15, 16, 17). Is it creating the same bindings multiple times? – Magnus Dec 11 '22 at 15:38
  • Hmmm @Bergi, I see that most of the *VarScopedDeclarations* and *LexicallyScopedDeclarations* return empty lists (ie no Parse Nodes). In fact, it seems only *LexicallyScopedDeclarations* return a Parse Node for *FunctionDeclaration*. Am I understanding that right? If so, does it ever get a positive assertion in step `8.a.i` of *GlobalDeclarationInstantiation*? – Magnus Dec 11 '22 at 19:06
  • 1
    Posted this as a separate question here: https://stackoverflow.com/questions/74768923/ecmascript-is-varscopeddeclarations-not-returning-functiondeclaration – Magnus Dec 12 '22 at 09:21