February 1999 Draft
JavaScript 2.0
Functions
|
Thursday, February 18, 1999
To define a function we use the following syntax:
getter
| setter
] function
Identifier (
Parameters )
[TypeExpression] BlockIf Visibility is absent, the above declaration defines a local function within the current Block scope. If Visibility is present, the above declaration declares either a global function (if outside a ClassDefinition's Block) or a class function (if inside a ClassDefinition's Block) according to the declaration scope rules.
The function's result type is TypeExpression, which defaults to type any
if not
given. If the function does not return a value, it's good practice to set TypeExpression to void
to document this fact.
Block contains the function body and is evaluated only when the function is called.
A function definition can also be traditional, which is more similar to the behavior of JavaScript 1.x function definitions.
Parameters has one of the following forms:
,
... ,
RequiredParameter [,
OptionalParameter ... ,
OptionalParameter] [,
...
[Identifier]]...
[Identifier]If the ...
is present, the function accepts more arguments than just the listed parameters.
If an Identifier is given after the ...
, then that Identifier
is bound to an array of arguments given after the listed parameters. That Identifier is
declared locally as though by the declaration const any[]
Identifier.
Individual parameters have the forms:
=
[AssignmentExpression]TypeExpression gives the parameter's type and defaults to type any
. If the parameter
name Identifier is followed by a =
, then that parameter is
optional. If the nth parameter is optional and a call to this function provides fewer than n arguments,
then the nth parameter is set to the value of its AssignmentExpression (or undefined
if the AssignmentExpression is missing), coerced to the nth parameter's type if necessary.
The nth parameter's AssignmentExpression is evaluated only if fewer than n
arguments are given in a call.
A RequiredParameter may not follow an OptionalParameter. If a
function has n RequiredParameters and m OptionalParameters
and no ...
in its parameter list, then any call of that function must supply at least
n arguments and at most n+m arguments. If this function has a ...
in its parameter list, then any call of that function must supply at least n arguments. These restrictions do not
apply to traditional functions.
The parameters' Identifiers are local variables with types given by the corresponding TypeExpressions inside the function's Block. Code in the Block may read and write these variables. Arguments are passed by value, so writes to these variables do not affect the passed arguments' values in the caller.
In addition to local variables generated by the parameters' Identifiers, each function also
has a predefined arguments
local variable which holds an array (of type const any[]
) of all
arguments passed to this function.
When a function is called, the following list indicates the order of evaluation of the various expressions in a FunctionDefinition. These steps are taken only after all of the arguments have been evaluated.
...
to the result.Note that later TypeExpressions and AssignmentExpressions can refer to previously bound arguments. Thus, the following is legal:
function choice(boolean a, type b, b c, b d=) b { return a ? c : d; }
The call choice(true,int,8,4)
would return 8
, while choice(false,int,6)
would return
0
(undefined
coerced to type int
).
Unless the function is a traditional function, the function definition using the above
syntax does not define a class; the function's name cannot be used in a new
expression, and the function
does not have a this
parameter. Any attempt to use this
inside the function's body is an error.
To define a method that can access this
, use the method
keyword.
If a FunctionDefinition is located at a class scope (either because it is located the top
level of a ClassDefinition's Block
or it has a Visibility prefix and is located inside a ClassDefinition's
Block), then the function is a static
method of the class. Unlike C++ or Java, JavaScript 2.0 does not use the static
keyword to indicate such functions;
instead, instance methods (i.e. non-static methods) are defined using the method
keyword.
If a FunctionDefinition contains the keyword getter
or setter
,
then the defined function is a getter or a setter.
A getter must not take any parameters and cannot have a ...
in its Parameters
list. Unlike an ordinary function, a getter is invoked by merely mentioning its name without an Arguments
list in any expression except as the destination of an assignment. For example, the following code returns the string <2,3,1>
:
var integer x = 0; getter function serialNumber() integer {return ++x} var y = serialNumber; return "<" + serialNumber + "," + serialNumber + "," + y + ">";
A setter must take exactly one required parameter and cannot have a ...
in its Parameters
list. Unlike an ordinary function, a setter is invoked by merely mentioning its name (without an Arguments
list) on the left side of an assignment or as the target of a mutator such as ++
or --
. The result
of the setter becomes the result of the assignment. For example, the following code returns the string <1,2,43>
:
var integer x = 0; getter function serialNumber() integer {return ++x} setter function serialNumber(integer n) integer {return x=n} var s = "<" + serialNumber + "," + serialNumber; serialNumber = 42; return s + "," + serialNumber + ">";
A setter can have the same name as a getter in the same lexical scope. A getter or setter cannot be extracted from its variable, so the notion of the type of a getter or setter is vacuous; a getter or setter can only be called.
Contrast the following:
var integer x = 0; function f() integer {return ++x} function g() funct {return f} getter function h() funct {return f} f; // Evaluates to function f g; // Evaluates to function g h; // Evaluates to function f (not h) f(); // Evaluates to 1 g(); // Evaluates to function f h(); // Evaluates to 2 g()(); // Evaluates to 3
We can use a getter and a setter to create an alias to another variable, as in:
getter function myAlias() {return Pkg::var} setter function myAlias(x) {return Pkg::var = x} myAlias = myAlias+4;
Traditional function definitions are provided for compatibility with JavaScript 1.x. The syntax is as follows:
traditional
function
Identifier (
Identifier ,
... ,
Identifier )
BlockA function declared with the traditional
keyword cannot have any argument or result
type declarations, optional arguments, or getter
or setter
keyword. Such a function is treated as though every argument were optional and more arguments than just the listed ones were
allowed. Thus, the definition
traditional
function
Identifier (
Identifier ,
... ,
Identifier )
Block
behaves like the following function definition:
function
Identifier (
Identifier =
,
... ,
Identifier =
,
...
)
Block
Furthermore, a traditional function defines its own class and treats this
in the same manner as JavaScript
1.x.
Every function (except a getter or a setter) is also a value and has type funct
. Like other values, it can
be stored in a variable, passed as an argument, and returned as a result. The identifiers in a function are all lexically
scoped.
We can use a variant of a function definition to define a function inside an expression. The syntax is:
function
[Identifier] (
Parameters )
[TypeExpression] BlockThis expression defines an anonymous function and returns it as a value of type funct
. The anonymous function
can be named by providing the Identifier, but this name is only useful to identify the function
in a debugger.
To avoid confusion between a FunctionDefinition and a FunctionExpression, a Statement (and a few other grammar nonterminals) may not begin with a FunctionExpression. To place a FunctionExpression at the beginning of a Statement, enclose it in parentheses.
A FunctionDefinition is merely convenient syntax for a const
variable definition
and a FunctionExpression:
[Visibility] function
Identifier (
Parameters )
[TypeExpression] Block
is equivalent to:
[Visibility] const
funct
Identifier =
function
Identifier (
Parameters )
[TypeExpression] Block ;
Unless a function is a getter or a setter, we call that function by listing its arguments in parentheses after the function expression, just as in JavaScript 1.x:
(
AssignmentExpression ,
... ,
AssignmentExpression )
Waldemar Horwat Last modified Thursday, February 18, 1999 |