9.8 Function Parameters Revisited
Now that we're comfortable with how functions work, let's return to the topic of function parameters. Our current discussion requires a little knowledge of objects, so new programmers may want to read Chapter 12 before reading this section.
9.8.1 Number of Parameters
Earlier we saw that the parameters of a function are declared when the function is created. Recall the syntax:
function
funcName
(
param1
,
param2
,
...paramn
) {
statements
}
Perhaps surprisingly, the number of parameters passed to a function can
differ
from the number specified in the formal function declaration. Functions can accept any number of parameters, whether more than or fewer than the "expected" number. When a function is called with fewer than the declared number of parameters, the value of each missing parameter is set to
undefined
. For example:
function viewVars (x, y, z) {
trace ("x is " + x);
trace ("y is " + y);
trace ("z is " + z);
}
viewVars(10); // In Flash Player 6, displays:
// x is 10
// y is undefined
// z is undefined
// (In Flash Player 5, undefined variables are displayed as a
// blank string in the Output window.)
When a function is called with
more
parameters than the declared number, excess parameter values can be accessed using the
arguments
object. (Obviously, the excess parameters can't be accessed by
name
, as explicitly declared parameters can, because their
names
were not declared.)
9.8.2 The arguments Object
During the execution of any function, the built-in
arguments
object gives us access to the following:
-
The number of parameters that were passed to the function
-
An array containing each of those parameter values
-
A reference to the function being executed
-
A reference to the calling function, if any
The
arguments
object is really a special hybrid between an array and an object with some other properties. In Flash 5,
arguments
was not an array instance. In Flash MX, however,
arguments
is an instance of the
Array
class and therefore supports
Array
's
methods
and properties.
9.8.2.1 Retrieving parameter values from the arguments array
The
arguments
array lets us check the value of any function invocation argument, whether or not that parameter is defined
formally
in the function's declaration statement. To access a parameter, we examine the indexes of the
arguments
array:
arguments[
n
]
where
n
is the index of the argument we're accessing. The first argument (the leftmost argument in the function-call invocation) is stored at index 0 and is referred to as
arguments[0]
. Subsequent arguments are stored in order, proceeding to the right—so, the second argument is
arguments[1]
, the third is
arguments[2]
, and so on.
From within a function, we can tell how many arguments were passed to the currently executing function by checking the number of elements in
arguments
, as
follows
:
numArgs = arguments.length;
We can easily cycle through all the arguments passed to a function and display the results in the Output window, as shown in Example 9-3.
Example 9-3. Displaying an unknown number of arguments
function showArgs () {
for (var i = 0; i < arguments.length; i++) {
trace("Argument " + (i + 1) + " is " + arguments[i]);
}
}
showArgs(123, 23, "skip intro");
// Displays...
Argument 1 is 123
Argument 2 is 23
Argument 3 is skip intro
The
arguments
array allows us to create very flexible functions that accept an arbitrary number of arguments.
Here's a generic function that
removes
any number of
duplicated
movie clip instances from the Stage:
function killClip () {
for (var i = 0; i < arguments.length; i++) {
arguments[i].removeMovieClip();
}
}
killClip(clip10, clip5, clip13);
Reader Exercise: Modify our earlier
combine( )
function to accept an arbitrary number of inputs. What other functions might benefit from accepting an arbitrary number of parameters? How about a function that averages a list of
numbers
? (Hint: sum all the arguments and then divide by the number of arguments.)
9.8.2.2 The callee and caller properties
As we've seen, the
arguments
array lets us retrieve a function's arguments. The
arguments
object has two properties:
callee
, which stores a reference to the executing function, and
caller
, which stores a reference to the function that called the current function (or
null
if no function called the current function).
Normally, we know the name of the function we're calling, but if we are executing an anonymous function that was originally created with a function literal, the
callee
property can
prove
useful. Example 9-4 shows a function, created with a function literal, that
performs
recursive executions without knowing its own name.
Example 9-4. Counting down with callee
count = function (x) {
trace(x);
if (x > 1) {
arguments.callee(x - 1);
}
}
count(25);
Obviously we can count down without using recursive anonymous functions. We'll see a more realistic example of function recursion in Section 9.9 later in this chapter. Using
arguments.callee
to refer to the current function (rather than the function's actual name) alleviates the need to update our code if the function's name changes.
We can use
arguments.caller
to execute or identify a calling function, as described in the
Language Reference
.
9.8.3 Passing Parameters by Value Versus by Reference
There's one more parameter subtlety we should consider—the difference between passing data to a function
by value
and
by reference
.
When we pass a primitive data value as an argument to a function, the function receives a copy of the data, not the original. Changes made to a parameter in the function have no effect on the original argument outside that function. In Example 9-5,
variableName
's value is initially set to 25. Changing its value to 10 within the
setValue( )
function has no effect on
y
's value.
Example 9-5. Primitive data is passed by value
var y = 25;
function setValue (variableName) {
variableName = 10;
}
setValue(y);
trace("y is " + y); // Displays: "y is 25"
Primitive data is therefore said to be
passed by value
. When we pass
composite
data as an argument to a function, however, the function receives a
reference
that points to the same data as the original argument, not just a duplicate of the data. Altering the data via the parameter variable affects the original data and therefore affects other variables that point to the same data, even outside of the function. Composite data is therefore said to be
passed by reference
.
In Example 9-6, changes to the
myArray
parameter variable affect the external
boys
array because they both point to the same data in memory.
Example 9-6. Modifying composite data arguments passed by reference
// Create an array
var boys = ["Andrew", "Graham", "Derek"];
//
setValue( )
sets the value of the first element of an array
function setValue (myArray) {
myArray[0] = "Sid"; // Set the first element of the array
}
// Pass our array to the function
setValue(boys);
// Check the value of our array elements
trace("Boys: " + boys); // Displays: "Boys: Sid,Graham,Derek"
Note that new values assigned to individual elements of the array from inside a function are reflected outside the function as well. However, suppose that instead of assigning new values to one or more elements, we assign a new value to the parameter itself. Doing so will break its association with the original argument. Subsequent changes to the parameter variable will have no effect on the original argument, as shown in Example 9-7. In this example, although the
boys
array is passed as an argument, the
myArray
parameter variable is immediately set to
girls
. Subsequent changes to
myArray
affect the
girls
array, not the
boys
array.
Example 9-7. Breaking the association between an argument and a parameter
// Create two arrays
var boys = ["Andrew", "Graham", "Derek"];
var girls = ["Alisa", "Gillian", "Daniella"];
//
setValue( )
ignores the passed array and modifies the
girls
array
function setValue (myArray) {
myArray = girls; // Make
myArray
point to
girls
, not
boys
myArray[0] = "Mary"; // Changes the first element of
girls
}
// Pass the
boys
array to the
setValue( )
function
setValue(boys);
trace("Boys: " + boys); // Displays: "Boys: Andrew,Graham,Derek"
trace("Girls: " + girls); // Displays: "Girls: Mary,Gillian,Daniella"
More information on primitive and composite data can be found in Chapter 3.
|