7.1. Defining and Invoking Functions
As
we saw in Chapter 6, the most common way to define
a function is with the function statement. This
statement consists of the function
keyword,
followed by:
-
The name of the function
-
An optional comma-separated list of parameter names in parentheses
-
The JavaScript statements that comprise the body of the function,
contained within curly braces
Example 7-1 shows the definitions of several
functions. Although these functions are short and simple, they all
contain each of the elements I just listed. Note that functions may
be defined to expect varying numbers of arguments and that they may
or may not contain a
return
statement. The return statement was introduced in
Chapter 6; it causes the function to stop
executing and to return the value of its expression (if any) to the
caller. If a function does not contain a return
statement, it simply executes each statement in the function body and
returns the undefined value to the caller.
Example 7-1. Defining JavaScript functions
// A shortcut function, sometimes useful instead of document.write( )
// This function has no return statement, so it returns no value
function print(msg)
{
document.write(msg, "<br>");
}
// A function that computes and returns the distance between two points
function distance(x1, y1, x2, y2)
{
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx*dx + dy*dy);
}
// A recursive function (one that calls itself) that computes factorials
// Recall that x! is the product of x and all positive integers less than it
function factorial(x)
{
if (x <= 1)
return 1;
return x * factorial(x-1);
}
Once
a function has been defined, it may be invoked with the (
) operator, introduced in Chapter 5.
Recall that the parentheses appear after the name of the function and
that an optional comma-separated list of argument values (or
expressions) appears within the parentheses. The functions defined in
Example 7-1 could be invoked with code like the
following:
print("Hello, " + name);
print("Welcome to my home page!");
total_dist = distance(0,0,2,1) + distance(2,1,3,5);
print("The probability of that is: " + factorial(39)/factorial(52));
When you
invoke a function, each of the expressions you specify between the
parentheses is evaluated and the resulting value is used as an
argument of the function. These values are assigned to the parameters
named when the function was defined, and the function operates on its
parameters by referring to them by name. Note that these parameter
variables are defined only while the function is being executed; they
do not persist once the function returns.
Since JavaScript is an untyped language, you are not expected to
specify a data type for function parameters, and JavaScript does not
check whether you have passed the type of data that the function
expects. If the data type of an argument is important, you can test
it yourself with the
typeof operator. JavaScript does not check
whether you have passed the correct number of arguments, either. If
you pass more arguments than the function expects, the extra values
are simply ignored. If you pass fewer than expected, some of the
parameters are given the undefined
value -- which, in many circumstances, causes your function to
behave incorrectly. Later in this chapter, we'll see a
technique you can use to test whether the correct number of arguments
have been passed to a function.
Note that the print( ) function does not contain a
return statement, so it always returns the
undefined value and cannot meaningfully be used as
part of a larger expression. The distance(
) and factorial( )
functions, on the other hand, can be invoked as parts of larger
expressions, as was shown in the previous examples.
7.1.2. The Function( ) Constructor
The function
statement is not the only way to define a new function. ECMAScript v1
and JavaScript 1.1 allow you to define a function dynamically with
the Function( ) constructor and the
new operator. (We saw the new
operator in Chapter 5, and we'll learn more
about constructors in Chapter 8.) Here is an
example of creating a function in this way:
var f = new Function("x", "y", "return x*y;");
This line of code creates a new function that is more or less
equivalent to a function defined with the familiar syntax:
function f(x, y) { return x*y; }
The Function( ) constructor expects any number of
string arguments. The last argument is the body of the
function -- it can contain arbitrary JavaScript statements,
separated from each other by semicolons. All other arguments to the
constructor are strings that specify the names of the parameters to
the function being defined. If you are defining a function that takes
no arguments, you simply pass a single string -- the function
body -- to the constructor.
Notice
that the Function( ) constructor is not passed any
argument that specifies a name for the function it creates. The
unnamed functions created with the Function( )
constructor are sometimes called anonymous
functions.
You might well wonder what the point of the Function(
) constructor is. Why not simply define all functions with
the function statement? One reason is that
Function( ) allows us to dynamically build and
compile functions; it does not restrict us to the precompiled
function bodies of the function statement. The
flip side of this benefit is that the Function( )
constructor has to compile a function each time it is called.
Therefore, you probably do not want to call this constructor within
the body of a loop or within a frequently used function.
Another reason to use the Function( ) constructor
is that it is sometimes convenient, and even elegant, to be able to
define a function as part of a JavaScript expression, rather than as
a statement. We'll see examples of this usage later in this
chapter. In JavaScript 1.2, when you want to define a function in an
expression rather than a statement, a function literal is an even
more elegant choice than the Function( )
constructor. We'll consider function literals next.
7.1.3. Function Literals
ECMAScript v3 defines and JavaScript
1.2 implements function literals, which are a third way to create
functions. As discussed in Chapter 3, a function
literal is an expression that defines an unnamed
function. The syntax for a function literal is much like that of the
function statement, except that it is used as an
expression rather than as a statement and no function name is
required. The following three lines of code define three more or less
identical functions using the function statement,
the Function( ) constructor, and a function
literal:
function f(x) { return x*x; } // function statement
var f = new Function("x", "return x*x;"); // Function( ) constructor
var f = function(x) { return x*x; }; // function literal
Although function literals create unnamed functions, the syntax
allows a function name to be optionally specified, which is useful
when writing recursive functions that call themselves. For example:
var f = function fact(x) { if (x <= 1) return 1; else return x*fact(x-1); };
This line of code defines an unnamed function and stores a reference
to it in the variable f. It does not actually
create a function named fact( ), but it does allow
the body of the function to refer to itself using that name. Note,
however, that this type of named function literal is not properly
implemented before JavaScript 1.5.
Keep in mind that the function statement is
available in all versions of JavaScript, the Function(
) constructor is available only in JavaScript 1.1 and
later, and function literals are available only in JavaScript 1.2 and
later. Recall that we said the three functions defined earlier are
"more or less" equivalent -- there are some
differences between these three techniques for function definition,
which we'll consider in Section 11.5.
Function literals are useful in much the same way as functions
created with the Function( ) constructor. Because
they are created by JavaScript expressions rather than statements,
they can be used in more flexible ways and are particularly suited
for functions that are used only once and need not be named. For
example, the function specified by a function literal expression can
be stored into a variable, passed to another function, or even
invoked directly:
a[0] = function(x) { return x*x; }; // Define a function and store it
a.sort(function(a,b){return a-b;}); // Define a function; pass it to another
var tensquared = (function(x) {return x*x;})(10); // Define and invoke
Like the Function( ) constructor, function
literals create unnamed functions and do not automatically store
those functions into properties. Function literals have an important
advantage over the Function( ) constructor,
however. The body of a function created by Function(
) must be specified in a string, and it can be awkward to
express long, complex function bodies in this way. The body of a
function literal, however, uses standard JavaScript syntax. Also, a
function literal is parsed and compiled only once, while the
JavaScript code passed as a string to the Function(
) constructor must be parsed and compiled each time the
constructor is invoked.