9.8. Function Parameters RevisitedNow 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, "Objects and Classes" before reading this section. 9.8.1. Number of ParametersEarlier we learned that the parameters of a function are declared when the function is created. Recall the syntax: function funcName (param1, param2, param3,...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); // Displays: "x is 10", "y is ", and "z is " because // y and z are undefined (and display as blanks) 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 like explicitly declared parameters because their names were not declared.) 9.8.2. The arguments ObjectDuring the execution of any function, the built-in arguments object gives us access to three pieces of information: (a) the number of parameters that were passed to the function, (b) an array containing each of those parameter values, and (c) the name of the function being executed. The arguments object is really a special hybrid between an array and an object with some other properties. 9.8.2.1. Retrieving parameter values from the arguments arrayThe arguments array lets us check the value of any function parameter 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 parameter we're accessing. The first parameter (the leftmost parameter in the function-call expression) is stored at index 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: arguments.length We can easily cycle through all the parameters 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 Parametersfunction showArgs( ) { for (var i = 0; i < arguments.length; i++) { trace("Parameter " + (i + 1) + " is " + arguments[i]); } } showArgs(123, 23, "skip intro"); // Displays... Parameter 1 is 123 Parameter 2 is 23 Parameter 3 is skip intro The arguments array allows us to create very flexible functions that accept an arbitrary number of parameters. 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 an arbitrary list of numbers? (Hint: sum all the arguments and then divide by the number of arguments.) 9.8.2.2. The callee propertyAs we've seen, the arguments array lets us retrieve a function's parameters. The arguments object has one property, callee, which returns a reference to the executing 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. See Section 9.9, "Recursive Functions" later in this chapter Example 9-4. Counting Down with calleecount = 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 later in this chapter. 9.8.3. Primitive Versus Composite Parameter ValuesThere's one more parameter subtlety we should consider -- the difference between passing primitive data and composite data to a function. 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 Valuevar 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, therefore, is 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 while we can overwrite individual elements of the array from inside a function, assigning a new value to a parameter will break its association with the original argument. Subsequent changes to the parameter variable will have no effect on the original argument. In Example 9-7, 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 15, "Advanced Topics". Copyright © 2002 O'Reilly & Associates. All rights reserved. |
|