Combining Statements into Functions

     

A function is an entire block of code that you can call, or invoke, from anywhere in a program. Calling the function causes the code in the function to execute. You can call a function using its name , if it has one. You can also call functions via variables , array elements, or object properties. All these ways of referring to a function are much more concise than the body of the function itself. These ways of referring to functions give you short, convenient "handles" for potentially complex behaviors.

Functions make it much easier to maintain programs. For instance, suppose you create a displayError() function to display error messages. If you ever want to change your error display function, you can make the change in only one place, in the displayError() function declaration. If instead you repeat a block of code multiple times, you have to edit each duplicate block individually.

Functions greatly improve both readability and reusability. They also make SWF files smaller by substituting a short function call for a longer repeated block of code. In addition, object-oriented programming (OOP) is founded on functions.

V For an introduction to functions, readability, reusability, and OOP, see Chapter 19, "Introduction to ActionScript," page 441 .


Function Basics: Creating Functions

There are two basics in using a function: creating it and calling it.

You can create a function in one of two ways, depending on whether or not you want it to have a permanent name of its own:

  • To create a function with its own permanent name, you declare the function.

  • To create a function with no permanent name of its own, you create a function literal . A function literal must be stored in a variable, an array element, or an object property to be referenceable.

Declaring Functions

When you declare a function, you permanently associate a function name with a block of code. The basic format for declaring a function is

 function  identifier  (  list  ):datatype {  statement1  ;  statement2  ; } 

where function is a keyword, identifier is the name of the function, list is an optional comma-separated list of arguments passed to the function, datatype is the data type of the value returned by the function, and statement1 and statement2 represent a series of ActionScript statements. The series can contain any number of statements.

The datatype is optional. If included, it applies strict data typing to the value returned by the function. You will get an error when you publish or test your program if the function returns a value of a different type than the declared datatype.

The name of the function must be a valid identifier, formed according to the rules set forth in "Rules for Naming Variables (and Other Things)" earlier in this chapter, page 462 .


Use Void to type a function that doesn't return anything. For instance, here is a declaration of a function with no arguments and no return value:

 function displayError():Void {      errorText = "Error!";      // error handling code } 

The idea is that this function updates a timeline variable that is displayed in a text field, notifying the user of an error.

Using Functions Without Names : Function Literals

A literal is an expression that represents a datum literally , as opposed to abstractly . It embodies the datum rather than naming it. A function literal is a function that you write out without giving it a name. Here's an example of a function literal:

 function () {      errorText = "Error!";      // error handling code } 

It looks just a like a function declaration with no name.

As with other literals, you need to store the function literal somewhere as soon as it's created, or it will be lost. You can store function literals in variables, for instance:

 displayError = function () {      trace("Error!"); }; 

In addition, you can store function literals as properties of objects:

 myObj = {prop1 : function(){trace("prop1");} ,          prop2 : function(){trace("prop2");} }; 

The following is another way of accomplishing the same thing. The first line creates an empty object. The second and third lines add properties to it. Each property refers to a function.

 myObj = {}; // create empty object myObj.prop1 = function(){trace("prop1");}; myObj.prop2 = function(){trace("prop2");}; 

The following example assigns the same functions as properties of an array:

 myArray = []; // create empty array myArray[0] = function(){trace("prop1");}; myArray[1] = function(){trace("prop2");}; 

Calling Functions

Declaring a function doesn't actually make anything happen in the program. To do that, you need to call or run the function. You call a function by using the function call operator, which is a pair of parentheses: () . The syntax for calling a function is straightforward:

  identifier  (  list  ); 

Here, identifier is the name of the function, and list is an optional comma-separated list of arguments.

Many ActionScript "actions" are built-in functions that you can call without declaring them. For example, nextFrame() is a built-in function that sends the playhead to the next frame and stops it. If a function has no arguments, the parentheses are left empty. Adding a semicolon completes the statement, as shown here:

 nextFrame(); 

You call custom functions (ones that you have created) in exactly the same way:

 displayError(); // invokes displayError() function 

Using var to Create Local Function Variables

Most functions contain one or more variables used only within the function. For instance, suppose you're writing a function, greet() , that returns one of three greetings ("good morning," "good afternoon," or "good evening") depending on the time of day. To determine the time in ActionScript, you create both a Date object (such as myDate ) and a variable to hold the time (such as hours ). You want to use myDate and hours only within the greet() function, but you may want to use those names again elsewhere in the program to refer to different objects or variables. Looking to the future, you also want to be able to drop this function into other programs and know that it will not cause a "name conflict" by using a name that is already in use in that program and therefore affect the items (such as variables or objects) in the other program with which it now inadvertently shares the name.

In a situation like this, you can use the var keyword to declare a local variable within a function. A local variable is available only within the function. A local variable does not change or refer to a variable of the same name outside the function. For instance:

 function greet():String {      var hours:Number;      var myDate:Date;      // code to get the time and return greeting      // all uses of hours and myDate remain local to the function } 

In the following example, the trace (myVar) statement displays the local variable, not the timeline variable of the same name:

 var myVar:String = "timeline"; function myFunc():Void {      var myVar:String = "local";      trace (myVar); // "local" } 

If you change var myVar:String = "local" to myVar = "local" the statement in the function refers to and changes the timeline variable of the same name! If you have a variable that you want to use just within a function, always declare it with var . Declaring it this way prevents you from inadvertently changing a timeline variable of the same name.

Arguments are also treated as local variables. Arguments are discussed later in this chapter, in the "Passing Information to Functions in Arguments section below.


The var Keyword Doesn't Work Outside Functions

Anywhere on a timeline other than inside a function, the var keyword has no effect. This includes event handlers! You can use var in an event handler, but it doesn't change anything. For instance, if you create a variable in a load event handler, as shown in the following example, it can change and be changed by statements on the movie clip timeline, in other event handlers, or on associated buttons :

 onClipEvent(load) {      var c = 10; // the "var" doesn't change anything } 

Accessing Timeline Variables Within a Function

If you have a function on a timeline, and you use var to create a local variable within the function, you can refer to a timeline variable of the same name by using the this keyword. Here, this refers to the current timeline. Variables created within the timeline are properties of that timeline, and therefore can be referenced using the dot operator. For example:

 myVar = "timeline"; function myFunc() {      var myVar = "local";      trace  (myVar); // "local"      trace (this.myVar); // "timeline" } 

Passing Information to Functions in Arguments

The displayError() function in the "Calling Functions" section earlier in this chapter can display only one message: "Error!" . Suppose you want to give the user more specific information about the error. You can do that, without creating a separate function for each error, by passing an argument to the displayError() function. In the following example, the argument is named arg . The arg parameter exists in memory only for the duration of the function. When the function terminates, arg disappears. It has completed its task in changing the errorText variable.

 function displayError(arg) {      var errorText:String = arg;      // error handling code } 

Then you can call the function for different errors, like this:

 displayError("Error: required field, cannot be left blank"); displayError("Error: password must be 8 or more characters"); displayError("Error: invalid zip code"); 

Adding arguments like this makes displayError() much more flexible and useful. In addition, it makes the function more reusable. For instance, you could easily plug in different error messages for a different program.

Note that declaring arguments does not limit the number of arguments that you can pass to a function. However, only arguments that are declared can be referred to within the function by name. You can access other arguments via the arguments object, as described in the section after next.

Passing Arguments by Value and by Reference

When a primitive datum is passed to a function as an argument, it is passed by value . That is, the interpreter allocates a new space in memory and copies the value of the datum into it. The function never sees the original datum, only the copy. If you change the copy within the function, the original is not affected.

On the other hand, composite data types (objects, arrays, functions) are passed by reference . That is, the interpreter creates a pointer to the original item and passes it to the function. Any changes made within the function do affect the original.

The arguments Object

When a function is invoked, it automatically gets a property named arguments , which is an array (or, in Macromedia Flash 5, an array-like object), with elements that can be accessed via numeric indices (starting with 0), and a length property specifying the number of array elements.

Each time a function is called, arguments is created and populated with all the arguments passed to the function. In addition, arguments.length is set to the number of arguments.

In Flash Player 5 and earlier, array methods such as push() and pop() do not work with the arguments property. In the Flash 6 Player and later, arguments is a real array with all the associated methods. In addition, the arguments.callee property shows up in a for-in loop in the Flash 5 Player, but not in the Flash Player 6 and later.

The arguments property is available only inside the function, while the function is executing. It can be referred to simply as arguments . Alternatively, it can be preceded by the function name ”for instance, myFunc.arguments .

In the following function, myFunc() , the trace(arg1) statement and the trace(arguments[0]) statement do exactly the same thing, namely, display the value of the first (and only) argument:

 function myFunc(arg1) {      trace(arg1); // displays "this is the argument"      trace(arguments[0]); // displays "this is the argument" } myFunc("this is the argument"); 

The arguments object has three properties:

  • length ” The length of the arguments array

  • callee ” The function that is currently executing

  • caller ” The function that called the currently executing function

NOTE

arguments.caller is available only in the Flash 6 Player and later, not the Flash 5 Player.


The preceding are properties of the object, not elements of the array. These three properties are present even if the arguments array has no elements ”that is, even if no arguments are passed.

Using the arguments.length Property

One use of the arguments.length property is to accommodate a variable number of arguments. For instance, the following avg() function returns the average of any number of arguments. The arguments array and the arguments.length property allow the avg() function to cope with a variable number of arguments:

 function avg():Number {      var sum:Number = 0;      // add up all the arguments      for(var i:Number = 0; i < arguments.length; i++) {           sum = sum + arguments[i];      }      // divide the sum by the number of arguments -- that's the average      var average:Number = sum/arguments.length;      return average; } trace("Average = " + avg(2,4,6)); // display "Average = 4" trace("Average = " + avg(10,20,30,40,50)); // display "Average = 30" 

Using the callee Property

The arguments.callee property gives you a way of calling a function from within the function, without using the function name. One use of arguments.callee is to make code more generic so that you can cut and paste more easily within and between programs.

With ordinary, named functions, using arguments.callee to create generic code is just a convenience. Each function has a fixed name, and you can always use it. In contrast, an anonymous function created by a function literal has no fixed name. At any given moment, it may be assigned to a particular variable, array element, or object property. But that assignment could change. In this case, using arguments.callee to create generic code is a safety measure ”it insures that your reference to the function will continue to work, no matter what the function's current name is.

For an example of the type of problem that arguments.callee can prevent, see callee.htm on the CD accompanying this book.


Using the caller Property

The caller property gives you a way to call the function that called the currently executing function. For instance:

 function calleeFunc() {      arguments.caller(); // call the caller back } 

In using arguments.caller , be sure that the caller will not call the callee right back, creating an infinite loop.

Using Return Values to Retrieve Results

Sometimes, you want a function not only to perform a task but also to return a value to you. For instance, if you write a function to double numbers, you don't just want it to double the numbers; you want it to pass the doubled numbers back to you so that you can do something with them. Functions supply return values in a return statement. A return statement with a return value returns that value to the caller, as in the following example, in which a function returns twice the value passed to it:

 function doubleIt(numberToBeDoubled:Number):Number {      return numberToBeDoubled * 2; } 

Notice that strict data typing is used twice in the preceding function declaration: The first Number says that the argument has to be a number. The second Number says that the function must return a number.

A function does not need to have a return statement. If it doesn't have one, the function will just execute its statements sequentially, top to bottom, and terminate when it comes to the final curly brace . A return statement terminates the function immediately on the line that contains the return statement. A return statement with no return value returns undefined .

graphics/troubleshooting_icon.jpg

Does part of your function seem "disabled"? Perhaps you're suffering from a premature return statement. See the "Troubleshooting" section at the end of this chapter, page 535 .


There are two ways to use a return value:

  • Assign the return value to a variable and use the variable in some way.

  • Use the function call itself as an expression.

For example, using the doubleIt() function, this is an example of the first approach:

 twicefour = doubleIt(4); trace(twicefour); // displays 8 

And this is an example of the second approach:

 trace(doubleIt(4)); // displays 8 

Both examples accomplish the same task. The second approach is half the size of the first, both in the source code and in the SWF. However, the second approach does not create a variable that you can continue to use. The first approach does.

graphics/troubleshooting_icon.jpg

Not getting the return you expect? See the "Troubleshooting" section at the end of this chapter, page 535 .


Functions as Classes: Constructor Functions

ActionScript 1 uses constructor functions as its only embodiment of classes. ActionScript 1 uses the constructor function, in combination with the new operator, to create new objects belonging to a class. This is no longer recommended. If you are going to be creating classes with Flash MX 2004, use the ActionScript 2 approach.

If you need to use the ActionScript 1 approach to creating classes (for compatibility with Flash Player 5, for instance), see functionsAsClasses.htm on the CD accompanying this book. You may also want to consult Special Edition Using Flash MX , published by Que in 2003.


For more on ActionScript 2 methods of creating classes, see "ActionScript 2.0: Real Class," page 540 , in Chapter 21.


Using Function.apply() and Function.call()

The apply() and call() methods, which are defined for all functions, enable you to call a function or method as if it were a method of any designated object. You specify the object as the first argument of the apply() or call() method. Inside the called function, the this keyword refers to the designated object.

Without the apply() and call() methods, when you call a function or method, you're stuck with a default value for this . For example, if you call a method, this refers to the object to which the method belongs. If you call a function on a timeline, this refers to the timeline.

For more details on this , see "Explicit Scoping with the this Keyword ," later in this chapter, page 495 .


With apply() and call() , you can make this refer to any object you want.

You can also pass any number of parameters to the called function. The only difference between apply() and call() is that apply() passes parameters in an array, whereas call() passes a comma-delimited list.

The format looks like this:

 myFunction.apply(myObject, myArray); myFunction.call(myObject, myArg1, myArg2, myArg3); 

The apply() or call() method receives whatever return value the function normally returns.

If the first argument is null , the default value of this is used. In this case, apply() and call() behave like normal function calls, except that apply() passes its parameters in an array.

You can also set the second argument to null , to show that you're deliberately not passing any parameters. This technique has the same effect as omitting the second argument completely.

The apply() method does not support associative arrays (arrays indexed by names rather than numbers) as its second argument. The named properties of the associative array are lost, and the called function receives only numerically indexed elements.

For more information on associative arrays, see "Named Array Elements: Associative Arrays," page 561 , in Chapter 21, "Advanced ActionScript."


You can use the arguments property of a function as the second argument of apply() . For instance, the following example first calls the myHandler() function with two arguments: 1 and 2 . The myHandler() function, in turn , calls the myDelegate() function. The myHandler() function "forwards" its arguments by using its arguments property as the second argument of the apply() method.

Notice how the return value returns from myDelegate() to myHandler() and then back to the original call.

The this keyword in myDelegate() refers to the timeline because the first argument of the apply() method was null . Thus, in the final trace action, p0 and p1 show up as ordinary timeline variables.

 function myDelegate ():Boolean {      this.p0 = arguments[0];      this.p1 = arguments[1];      return true; } function myHandler():Boolean {      ret = myDelegate.apply (null, arguments); // "forwarding" arguments      return ret; } result = myHandler(1,2); trace (result); // true trace (p0 + " " + p1); // 1 2 

Explicit Scoping

Scoping is telling the ActionScript interpreter where to look for a variable, movie clip, object, or array. The interpreter can look in a class , in a function , in an object , in a timeline , in the Object object, or in _ global . You can tell it specifically where to look, and then it looks in just that one place. That is explicit scoping, the subject of this section. Or you may deliberately not tell the interpreter where to look, and then it follows its own automatic scoping rules. That type of scoping is covered next, in the "Automatic Scoping" section.

Scope is like a sophisticated filing system. You can use it both to find things and to keep things private. Unfortunately, misfiling is also possible: Subtle bugs can result when the ActionScript interpreter is unable to find something or finds the wrong thing.

NOTE

In this section, timeline or movie clip means a movie clip timeline and any attached event handlers and buttons.


One way to avoid this type of problem is to use explicit scoping to tell the ActionScript interpreter exactly where to look. With explicit scoping, you use dot syntax (or deprecated slash syntax) to tell the ActionScript interpreter where to look for the data item that you're referencing. For instance:

 _root.myClip.myFunc(); // tells interpreter to look in a movie clip "myClip" _global.myVar = 10; // look in _global 

The Limitations of Hard-Coding

Using the name of a class, movie clip, function, object, or the _global identifier to specify the path (location) of a datum, as in the previous examples, is an example of hard-coding . Though clear and often easy to use, hard-coded paths make code less reusable. In the root.myClip.myFunc(); example, for instance, if you want to use the myFunc() function in another project but need to use it somewhere other than a movie clip named myClip in _root , you need to do some recoding. The same holds true in the second example, if you want to reuse myVar but don't want it to be a global variable.

You may be able to avoid hard-coding by using relative references or by using the this keyword. Another possibility is to use automatic rather than explicit scoping.

Explicit Scoping with Relative References

When you're scoping to a movie clip, a common way of making code more reusable is to use r elative references . That is, use the _parent property of the current movie clip to indicate the movie clip to look in. For instance:

 _parent.myFunc(); // look in the parent of the clip this appears in _parent._parent.myFunc(); // look in the "grandparent" of this clip 

Suppose, for example, myFunc() is in a movie clip named mc1 on the main timeline, making the absolute path of the clip _ root.mc1 . (Any path that begins with _root is called an "absolute path," because it gives you the location of the movie clip starting from the Main Timeline, not relative to any other movie clip.) Now, if you want to reference myFunc() from a child clip ”say, _ root.mc1.mc2 ”you can use _parent.myFunc() . In a grandchild clip ”say, _ root.mc1.mc2.mc3 ”you can use _parent._parent.myFunc() . Later, if you use this code with movie clips myClip1 , myClip2 , and myClip3 , nothing about the code needs to change to accommodate the different instance names of the movie clips.

Explicit Scoping with the this Keyword

The third type of explicit scoping uses the this keyword. With one major exception, this refers to the movie clip where the statement is located. The next section gives some examples of the general rule. The section after that covers the exception.

In a timeline (including attached event handlers and buttons), this usually refers to the timeline. You can use the this keyword in movie clips to get the ActionScript interpreter to recognize that you're invoking a MovieClip method, as opposed to the global function of the same name. For instance, if you put this code on a timeline, the ActionScript interpreter thinks you're invoking the global duplicateMovieClip() function, which requires three parameters. Because there are only two parameters here, you get an error:

 duplicateMovieClip("myClip",1); // ERROR!!! 

By inserting the this keyword, you invoke the MovieClip method, which requires only two parameters, and all is well:

 this.duplicateMovieClip("myClip",1); // no problem 

The following example shows three uses of this on a timeline, each of which causes a variable to scope to the timeline:

  • The variable is in a property of an object on the timeline.

  • The variable is referenced inside a function.

  • The variable is referenced in the movie clip directly.

The three trace statements at the end prove that the interpreter sees this as the timeline in each case. If c equals 300 , you can conclude that the statement is "seeing" a and b on the timeline. If it were seeing the a and b properties in the myObj object, for example, c would equal 3 , not 300 .

 a = 100; // variable declared on movie clip timeline b = 200; // variable declared on movie clip timeline c = a + b; // variable declared on movie clip timeline myObj = {a : 1, b : 2, c : this.a + this.b} // #1 "this" in a property function myFunc() {      trace(this.c); // #2 this in a function } trace(this.c); // # 3 this on the timeline - displays 300 trace(myObj.c); // displays 300 - in an object myFunc(); // displays 300 - in a function 

The variable scopes to the timeline that it is on, even if it is used inside an object or function. Perhaps surprisingly, the interpreter does not check within the object first for properties that match the referenced name.

Exception: Scoping to the Object

In the previous section, you saw that, in most situations, if you see this as the path of a variable on a timeline, this means the timeline. There is one notable exception ”namely that within a method of an object , this scopes to the object.

Other than that, the scoping rules for functions are the same as for variables. That is, on a timeline (or associated event handlers and buttons), or within a function on the timeline, this.myFunc() scopes to the timeline.

The following example does basically the same thing as the previous example, using functions instead of variables. The four function calls at the end (lines 10 “13) tell the story. The first one shows that when you reference this.a() on the timeline, the interpreter looks for a() on the timeline. Similarly, when you reference a() within b() , as in the function invoked on line 11, the interpreter looks for a() on the timeline. The third function call (line 12) shows that invoking this.a() from within a function, myFunc() , on the timeline, doesn't change anything: The interpreter still looks for a() on the timeline. The final function call, however, shows that when you say this.a() within a method, the interpreter looks for a() in the object the method belongs to.

 1: function a () {trace ("function a");} 2: function b () {this.a();} // "this" scopes to timeline here 3: myObj = { 4:      a : function () {trace ("object function a");}, 5:      b : function () {this.a();} // this scopes to the object! 6: }; 7: function myFunc() { 8:      this.a(); // "this" scopes to timeline here 9: } 10: this.a(); // displays "function a" - "this" scopes to timeline here 11: b();// displays "function a" 12: myFunc(); // displays "function a" 13: myObj.b(); // displays "object function a" 

Function Aliases Retain Their Own Scope

If you set a variable equal to a function or method, the variable maintains its own scope as a variable. It does not adopt the scope of the function or method. Therefore, a variable that is supposedly "equal to" a function may behave very differently from the function, because of its different scope. For instance, in the following example, the variable myAliasFunc is set equal to the function myObj.myFunc . Executing myObj.myFunc() displays prop1 correctly because it uses the method, which scopes to the object. However, executing myAliasFunc() displays undefined (or, in Flash 5, a blank line) because myAliasFunc scopes to the timeline, where there is no such variable as prop1 .

 myObj = new Object(); myObj.myFunc = function () {   trace(this.prop1); } myObj.prop1 = 1; myAliasFunc = myObj.myFunc; myObj.myFunc(); // displays "1" myAliasFunc (); // undefined, this.prop1 is undefined in the timeline 

Automatic Scoping

With automatic scoping, you simply make a direct reference to the variable, function, object, or array, with no dot syntax. You let the ActionScript interpreter scope your datum automatically.

For example, this is a direct reference:

 myFunc(); // does not tell the interpreter where to look for myFunc() 

In this case, the interpreter starts its search wherever you make the data reference. From there, it may search in movie clip timelines (including associated event handlers and buttons), functions, or objects, including inheritance chains. As a last resort, it looks in _global .

By default, ActionScript scope chains are very simple. The scope chain is the list of objects to be searched. Unless you create a more complicated structure by using the object-oriented programming (OOP) techniques, the scope chain is usually global - Object -timeline or _global - Object -timeline-function. The interpreter searches these chains from right to left ”for instance, the function first, then the timeline, then Object , and finally the _global object.

Longer chains do occur, such as _global - Object -timeline-outer function-inner function, in which the inner function is declared within the outer function.

You temporarily lengthen the scope chain when you use the with statement, which tacks on another object at the lowest level of the scope chain. That tacked-on object (the object in the with statement) is always checked first within the with statement. It is removed from the scope chain when the with statement terminates.

The following three examples show a starting point (where the variable or function is declared) and the typical resulting scope chain:

  • Start on a timeline (or attached event handler or button).

    Example:

     myFunc; // on a timeline 

    Scope chain : _global - Object -timeline.

    Note : The scope chain does not include other timelines.

  • Start in an object property or array element on a timeline.

    In this example, the myVar variable is declared on the timeline and referenced as the myObj.myProp1 property. That property is then displayed in two ways: using a method of the object, myMethod() , defined on line 4 and called on line 5; and using a trace statement on the timeline, on line 6.

     1: myVar = "main"; 2: myObj = { myVar : "myVarObj", 3:           myProp1 : myVar, 4:           myMethod : function () {trace(this.myProp1);}}; 5: myObj.myMethod(); // displays "main" 6: trace(myObj.myProp1); // displays "main" 

    Scope chain : _global - Object -timeline.

    Note 1 : If the value of myProp1 on line 3 is this.myVar (note the added this ), the scope chain is still _global - Object -timeline.

    Note 2 : The scope chain does not include "sibling" properties or elements. For instance, line 2 contains a myObj.myVar property, but it is ignored.

  • Start in a function or method declaration.

    In the following example, the myVar variable, after being declared on the timeline (line 1), is referenced first in a function declaration that is on the timeline (line 3) and then in a method myObj.myFunc() (line 5). (Note: myVar : 99 does not reference the timeline variable. Instead, it defines an object property of the same name.)

     1: myVar = 10; 2: function myFunc() { 3:      trace(myVar); 4: } 5: myObj = {myVar : 99 , myFunc : function() { trace(myVar);} } 6: myFunc(); // 10 7: myObj.myFunc(); // 10 

    Scope chain : _global - Object -timeline-function.

    Note : The scope chain does not include "sibling" properties. For instance, the interpreter ignores the myVar : 99 property (line 5).

The last statement (line 7), myObj.myFunc() , works identically in Flash Player 5 and later players, assuming it is on the same timeline as the declaration of myObj above it (line 5). However, if you tried to execute the myObj.myFunc() method from another timeline, it would fail in Flash Player 5 (or display a myVar variable on the other timeline, if one existed). In Flash Player 6 and later, you can execute the myObj.myFunc() method from another timeline, and it displays the myVar variable on the timeline where myObj is defined.

For instance, suppose the preceding code is on the Main Timeline, and you have a "circle" clip on the Main Timeline with the following statements on its timeline:

 myVar = "circle"; _parent.myObj.myFunc(); // displays "circle" in Flash 5, 10 in Flash MX 

The second statement displays "circle" in Flash Player 5. It displays "10" in Flash Player 6 and later. In Flash Player 6 and later, a method consistently takes the scope of the timeline where it is defined, never the timeline from which it is called. (Flash Player 6 and later conform to ECMA-262 in this respect, whereas Flash Player 5 deviated from it.)

Also in Flash Player 6 and later, a function literal defined within a function takes the scope of the outer function. In Flash Player 5, it took the scope of the timeline.

In the following example, innerFunction() refers to a function literal within outerFunction() . In Flash Player 6 and later, the function literal is scoped to outerFunction() and thus has access to the parameter arg . Therefore, when the function literal is returned in line 4, it includes the argument, which is displayed when the function executes in line 5. In Flash Player 5, innerFunction() is scoped to the timeline, on which arg is undefined, so line 5 displays "Argument was: " .

 1: function outerFunction (arg) { 2:      return innerFunction = function () {trace ("Argument was: "+arg);} 3: } 4: myFunc = outerFunction("myArg"); 5: myFunc(); // in Flash MX, displays "Argument was: myArg" 

This is an example of a five-link scope chain: _global - Object -timeline-outer function-inner function.

The following makeHandler() function shows how you can use this FP6 and later functionality to attach event handler functions to a movie clip programmatically. The makeHandler() function returns the name argument in FP6 and later. In FP5, it would return undefined (assuming there is no name variable on the timeline) because the inner function would not scope to the outer function.

 // thanks to Gary Grossman, principal engineer, Macromedia Flash team! function makeHandler(name) {     return function () {       trace("Handler  "+ name +"  invoked.");     };   }   function makeHandlers(mc, names) { // mc is a movie clip instance     for (var i=0; i<names.length; i++) {       mc[names[i]] = makeHandler(names[i]);       mc[names[i]](); // displays "Handler  onPress  invoked." etc.     }   }   makeHandlers(mc, ["onPress", "onRelease", "onReleaseOutside",                "onRollOver", "onRollOut", "onDragOver", "onDragOut"]); 

graphics/troubleshooting_icon.jpg

See the "Troubleshooting" section, page 535 , later in this chapter for a discussion of the possibility of timing (position on the timeline) making a variable or function inaccessible even within a single timeline .




Using Macromedia Studio MX 2004
Special Edition Using Macromedia Studio MX 2004
ISBN: 0789730421
EAN: 2147483647
Year: N/A
Pages: 339

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net