13 Function definition

2010-05-23

FunctionDeclaration :
function Identifier ( FormalParameterList(opt) ){ FunctionBody }

FunctionExpression :
function Identifier(opt) ( FormalParameterList(opt) ){ FunctionBody }

FormalParameterList :
Identifier
FormalParameterList , Identifier

FunctionBody :
SourceElements(opt)

Note that even though FunctionDeclaration and FunctionExpression define an exactly equal reading, no ambiguity is introduced because the two Productions are used in different contexts and could never be the child of the same parent Production.

As you can see, there is no FunctionStatement here. The function declaration is the function that is parsed ahead of execution (also called "hoisting"). The Expression simply creates and returns a function object at execution time.

This is what happens for FunctionDeclarations during Declaration Binding Instantiation (10.5, step 5).

Code: (Meta Ecma)
function evaluate(function Identifier ( FormalParameterList ){ FunctionBody }) {
var rec = global.arrExecutionContexts[global.arrExecutionContexts.length-1];
return CreateNewFunctionObject(FormalParameterList, FunctionBody, rec.VariableEnvironment, FunctionDeclaration.strict || FunctionBody.strict);
}

And this is a function expression, note that it gets the lexical environment, where the declaration gets the variable environment.

Code: (Meta Ecma)
function evaluate(function ( FormalParameterList(opt) ){ FunctionBody }) {
var rec = global.arrExecutionContexts[global.arrExecutionContexts.length-1];
return CreateNewFunctionObject(FormalParameterList, FunctionBody, rec.LexicalEnvironment, FunctionDeclaration.strict || FunctionBody.strict);
}

Note how the closure to Identifier is handled to allow recursive calls from within the function. However, the Identifier is not bound in the scope the FunctionExpression appears in. This means that this scope can NOT refer to that Identifier. This is only possible with a FunctionDeclaration, which registers the Identifier in the containing scope during Declaration Binding Instantation (10.5).

Code: (Meta Ecma)
function evaluate(function Identifier ( FormalParameterList(opt) ){ FunctionBody }) {
var rec = global.arrExecutionContexts[global.arrExecutionContexts.length-1];
var funcEnv = NewDeclarativeEnvironment(rec.LexicalEnvironment);
var envRec = funcEnv.environmentRecord; // meta api?
envRec.CreateImmutableBinding(Identifier);
var closure = CreateNewFunctionObject(FormalParameterList, FunctionBody, funcEnv, FunctionDeclaration.strict || FunctionBody.strict);
envRec.InitializeImmutableBinding(Identifier, closure);
return closure;
}


Code: (Meta Ecma)
function evaluate(SourceElements(opt)) {
// "the code of this functionbody is strict code if its part of a functiondeclaration or functionepxression that is contained in strict mode code, sourcelements is evaluated in the following steps as strict code. Otherwise sourceelements is evaluated in the following steps as non-strict mode code.
if (SourceElements) return evaluate(SourceElements);
return Completion('normal', undefined, empty); // undefined is a literal, not "empty"...
}