| Function.apply( ) Method | Flash 6 |
| invoke a function as an object method, passing parameters in an array |
The object on which theFunction is called as a method.
An array of values passed as arguments to theFunction.
The return value of theFunction.
The apply( ) method invokes theFunction as a method of thisObj and passes the values of parametersArray to theFunction as arguments. Within theFunction, the value of the this keyword is a reference to thisObj. The return value of apply( ) is simply the return value of theFunction. To invoke theFunction without specifying an object reference, use null as the value of thisObj. To pass a comma-delimited list of arguments to theFunction, instead of passing the values in a parametersArray, use Function.call( ).
The apply( ) method is normally used to alter the value of the this keyword when running a function, or to supply an array of arguments to a function in place of a comma-delimited list.
The following code shows the basic syntax of apply( ):
// Create a function
function square (x) {
return x*x;
}
// Invoke the function as a method of _root, passing an array literal
// containing the single argument value 10.
tenSquared = square.apply(_root, [10]);
This example has little practical purpose—it would be easier to invoke the function directly, as in: _root.square(10);. The apply( ) method becomes more useful when we need to dynamically specify the object on which to invoke a method, for example, when we want to use one method with many different objects that do not share a common class or superclass. Suppose we have getWidth( ) and moveClipTo( ) methods that we want to use with both a rectangle and a circle object. Here's the code we can use to create a generic method, Rectangle.invokeAsMethod( ), that invokes getWidth( ), moveClipTo( ), or any other function as a method of a rectangle object:
// A Rect class
function Rect (width, height, x, y) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
// Method to invoke any passed func as a method of a Rect object.
// Note that func is a function reference, not a string.
Rect.prototype.invokeAsMethod = function (func) {
// Invoke func as a method of this Rect, passing along any
// arguments that were supplied.
func.apply(this, arguments.slice(1));
};
// A simple generic getWidth function that takes no arguments
function getWidth () {
trace("width: " + this.width);
return this.width;
}
// A slightly more complex example, moveClipTo, that takes arguments
function moveClipTo (newX, newY) {
this.x = newX;
this.y = newY;
}
// Make a new Rect object
box = new Rect(15, 20);
// Invoke getWidth on box
box.invokeAsMethod(getWidth); // Displays: width: 15
// Invoke moveClipTo on box, passing the newX and newY arguments
box.invokeAsMethod(moveClipTo, 100, 200);
// Check if it worked...
trace("box x: " + box.x); // Displays: box x: 100
trace("box y: " + box.y); // Displays: box y: 200
This practice is not necessarily recommended when the objects can logically be assigned a common class or superclass. For example, rather than use apply( ) in our rectangle example, it's more appropriate to create a Shape superclass that defines moveClipTo( ) and getWidth( ) methods inherited by both Rect and Circle. For a more legitimate application of the apply( ) method, see the CountDown class shown in the following Example.
The following class, CountDown, invokes a specified object's method after a delay. It uses apply( ) to ensure that the method executes on the correct object and to pass the method arguments as a convenient array.
/*
* CountDown Class
* Desc: Calls a method after delay milliseconds.
* Params: obj An object whose method will be called.
* meth The string method name to call.
* delay The time (milliseconds) to wait before calling.
* arg4...argn The arguments to pass to meth.
*/
function CountDown (obj, meth, delay) {
// Remember how long to wait before calling meth.
this.delay = delay;
// Store a reference to the method.
this.callback = obj[meth];
// Store a reference to the object.
this.obj = obj;
// Store extra arguments. We'll pass them to meth later.
this.args = arguments.slice(3);
// Set an empty intervalID. Used with setInterval().
this.intervalID = -1;
// Start the countdown
this.start();
}
/*
* Method: start()
*/
CountDown.prototype.start = function () {
// Invoke the method-caller after this.delay milliseconds.
this.intervalID = setInterval(this, "invokeCallback", this.delay);
};
/*
* Method: stop()
*/
CountDown.prototype.stop = function () {
// Stop the interval so that it doesn't call the method again.
clearInterval(this.intervalID);
this.intervalID = -1;
};
/*
* Method: invokeCallback()
*/
CountDown.prototype.invokeCallback = function () {
// Time's up! Stop the countdown.
this.stop();
// Invoke the callback as a method of this.obj, and pass
// along this.args to use as method arguments.
this.callback.apply(this.obj, this.args);
};
// SAMPLE USE
// Create the countdown. Will invoke
// _root.output("hello", "world") after 1000 milliseconds.
count = new CountDown(_root, "output", 1000, "hello", "world");
// The method to invoke
function output (arg1, arg2) {
trace("output: " + arg1 + ", " + arg2);
}
Function.call( ), the Arguments object; Chapter 12