13 Function Definition

Syntax

FunctionDeclaration :
function Identifier ( FormalParameterListopt ){ FunctionBody }
FunctionExpression :
function Identifieropt ( FormalParameterListopt ){ FunctionBody }
FormalParameterList :
Identifier
FormalParameterList
, Identifier
FunctionBody :
SourceElements

Semantics

The production FunctionDeclaration : function Identifier ( FormalParameterListopt ){ FunctionBody } is processed for function declarations as follows:

1. Create a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt, and body specified by FunctionBody. Pass in the scope chain of the running execution context as the Scope.

2. Create a property of the current variable object (as specified in 10.1.3) with name Identifier and value Result(1).

The production FunctionExpression : function ( FormalParameterListopt ){ FunctionBody } is evaluated as follows:

1. Create a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the scope chain of the running execution context as the Scope.

2. Return Result(1).

The production FunctionExpression : function Identifier ( FormalParameterListopt ){ FunctionBody } is evaluated as follows:

1. Create a new object as if by the expression new Object().

2. Add Result(1) to the front of the scope chain.

3. Create a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the scope chain of the running execution context as the Scope.

4. Create a property in the object Result(1). The property's name is Identifier, value is Result(3), and attributes are { DontDelete, ReadOnly }.

5. Remove Result(1) from the front of the scope chain.

6. Return Result(3).

NOTE
The Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression
.

The production FunctionBody : SourceElements is evaluated as follows:

1. Process SourceElements for function declarations.

2. Evaluate SourceElements.

3. Return Result(2).

13.1 Definitions

A couple of definitions are needed to describe the process of creating function objects:

13.1.1 Equated Grammar Productions

Two uses of the FunctionBody grammar production are defined to be equated when one of the following is true:

NOTE
Two uses of FunctionBody obtained from a call to the Function constructor 15.3.1 and 15.3.2) are never equated. Also, two uses of FunctionBody obtained from two different calls to eval are never equated, even if those two calls to eval were passed the same argument
.

13.1.2 Joined Objects

When two or more Function objects are joined, they have the following special behaviours:

NOTE
Two or more objects joined to each other are effectively indistinguishable except that they may have different internal properties. The only such internal property that may differ in this specification is [[Scope]]
.

Joined objects are used as a tool for precise specification technique in this standard. They are not meant to be used as a guideline to how Function objects are implemented in practice. Rather, in practice an implementation may detect when the differences in the [[Scope]] properties of two or more joined Function objects are not externally observable and in those cases reuse the same Function object rather than making a set of joined Function objects. This is a legal optimisation because this standard only specifies observable behaviour of ECMAScript programs.

13.2 Creating Function Objects

Given an optional parameter list specified by FormalParameterList, a body specified by FunctionBody, and a scope chain specified by Scope, a Function object is constructed as follows:

1. If there already exists an object E that was created by an earlier call to this section's algorithm, and if that call to this section's algorithm was given a FunctionBody that is equated to the FunctionBody given now, then go to step 13. (If there is more than one object E satisfying these criteria, choose one at the implementation's discretion.)

2. Create a new native ECMAScript object and let F be that object.

3. Set the [[Class]] property of F to "Function".

4. Set the [[Prototype]] property of F to the original Function prototype object as specified in 15.3.3.1.

5. Set the [[Call]] property of F as described in 13.2.1.

6. Set the [[Construct]] property of F as described in 13.2.2.

7. Set the [[Scope]] property of F to a new scope chain (10.1.4) that contains the same objects as Scope.

8. Set the length property of F to the number of formal properties specified in FormalParameterList. If no parameters are specified, set the length property of F to 0. This property is given attributes as specified in 15.3.5.1.

9. Create a new object as would be constructed by the expression new Object().

10. Set the constructor property of Result(9) to F. This property is given attributes { DontEnum }.

11. Set the prototype property of F to Result(9). This property is given attributes as specified in 15.3.5.2.

12. Return F.

13. At the implementation's discretion, go to either step 2 or step 14.

14. Create a new native ECMAScript object joined to E and let F be that object. Copy all non-internal properties and their attributes from E to F so that all non-internal properties are identical in E and F.

15. Set the [[Class]] property of F to "Function".

16. Set the [[Prototype]] property of F to the original Function prototype object as specified in 15.3.3.1.

17. Set the [[Call]] property of F as described in 13.2.1.

18. Set the [[Construct]] property of F as described in 13.2.2.

19. Set the [[Scope]] property of F to a new scope chain (10.1.4) that contains the same objects as Scope.

20. Return F.

NOTE
A prototype property is automatically created for every function, to allow for the possibility that the function will be used as a constructor
.

Step 1 allows an implementation to optimise the common case of a function A that has a nested function B where B is not dependent on A. In this case the implementation is allowed to reuse the same object for B instead of creating a new one every time A is called. Step 13 makes this optimisation optional; an implementation that chooses not to implement it will go to step 2.

For example, in the code

function A() {
   function B(x) {return x* x;} 
   return B; 
}

function C() { 
  return eval("(function(x) {return x* x;})"); 
}

var b1 = A(); 
var b2 = A(); 
function b3(x) {return x* x;} 
function b4(x) {return x* x;} 
var b5 = C(); 
var b6 = C();

an implementation is allowed, but not required, to join b1 and b2. In fact, it may make b1 and b2 the same object because there is no way to detect the difference between their [[Scope]] properties. On the other hand, an implementation must not join b3 and b4 because their source codes are not equated (13.1.1). Also, an implementation must not join b5 and b6 because they were produced by two different calls to eval and therefore their source codes are not equated.

In practice it's likely to be productive to join two Function objects only in the cases where an implementation can prove that the differences between their [[Scope]] properties are not observable, so one object can be reused. By following this policy, an implementation will only encounter the vacuous case of an object being joined with itself.

13.2.1 [[Call]]

When the [[Call]] property for a Function object F is called, the following steps are taken:

1. Establish a new execution context using F's FormalParameterList, the passed arguments list, and the this value as described in 10.2.3.

2. Evaluate F's FunctionBody.

3. Exit the execution context established in step 1, restoring the previous execution context.

4. If Result(2). type is throw then throw Result(2). value.

5. If Result(2). type is return then return Result(2). value.

6. (Result(2). type must be normal.) Return undefined.

13.2.2 [[Construct]]

When the [[Construct]] property for a Function object F is called, the following steps are taken:

1. Create a new native ECMAScript object.

2. Set the [[Class]] property of Result(1) to "Object".

3. Get the value of the prototype property of F.

4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).

5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.

6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.

7. If Type(Result(6)) is Object then return Result(6).

8. Return Result(1).