home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book HomeActionScript: The Definitive GuideSearch this book

2.5. Variable Scope

Earlier we learned how to create variables and retrieve their values using variables attached to a single frame of the main timeline of a Flash document. When a document contains multiple frames and multiple movie clip timelines, variable creation and value retrieval becomes a little more complicated.

To illustrate why, let's consider several scenarios.

2.5.2. Scenario 2

Suppose we create and set x as we did in Scenario 1, but instead of placing the variable-setting code on frame 1 directly, we place it on a button in frame 1. Then, on frame 2, we attach the same code as before:

trace(x);

Does Scenario 2 also work? Yes. Because x is attached to our button, and our button is attached to the main timeline, our variable is indirectly attached to the main timeline. We may, therefore, access the variable from frame 2 as we did before.

2.5.5. Movie Clip Variables

As we saw in the three earlier scenarios, a variable defined on a timeline is available to all the scripts on that timeline -- from the first frame to the last frame -- whether the variable is declared on a frame or a button. But what happens if we have more than one timeline in a movie, as described in Scenario 4?

2.5.5.1. Scenario 4

Suppose we have two basic geometric shapes, a square and a circle, defined as movie clip symbols.

On frame 1 of the square clip symbol, we set the variable x to 3:

var x;
x = 3;

On frame 1 of the circle clip symbol, we set the variable y to 4:

var y;
y = 4;

We place instances of those clips on frame 1, layer 1 of the main timeline of our movie and name our instances square and circle.

First question: If we attach the following code to frame 1 of the main movie timeline (upon which square and circle have been placed), what appears in the Output window? Here's the code:

trace(x);
trace(y);

Answer: Nothing appears in the Output window. The variables x and y are defined on the timelines of our movie clips, not our main timeline.

TIP

Variables attached to a movie clip timeline (like that of square or circle) have scope limited to that timeline. They are not directly accessible to scripts on other timelines, such as our main movie timeline.

Second question: If we were to place the trace(x) and trace(y) statements on frame 1 of our square movie clip instead of frame 1 of our main movie timeline, what would appear in the Output window?

Answer: The value of x, which is 3, and nothing else. The value of x is displayed because x is defined on the timeline of square and is therefore accessible to the trace( ) command, which also resides on that timeline. But the value of y, which is 4, doesn't appear in the Output window because y is defined in circle, which is a separate timeline.

You can now see why I said that ActionScript doesn't support true global variables. Global variables are variables that are accessible throughout an entire program, but in Flash, a variable attached to an individual timeline is directly accessible only to the scripts on that timeline. Since all variables in Flash are defined on timelines, no variable can be guaranteed to be directly accessible to all the scripts in a movie. Hence, no variable can legitimately be called global.

To prevent confusion, we refer to variables attached to timelines as timeline variables or movie clip variables. However, it is possible to simulate global variables using the Object class. To create a variable that is available on all timelines, use the following statement:

Object.prototype.myGlobalVariable = myValue;

For example:

Object.prototype.msg = "Hello world";

This technique (and the reason it works) is discussed under Section 12.5.4.4, "The end of the inheritance chain" in Chapter 12, "Objects and Classes".

2.5.6. Accessing Variables on Different Timelines

Even though variables on one timeline are not directly accessible to the scripts on other timelines, they are indirectly accessible. To create, retrieve, or assign a variable on a separate timeline, we use dot syntax, a standard notation common to object-oriented programming languages such as Java, C++, and JavaScript. Here's the generic dot syntax phrasing we use to address a variable on a separate timeline:

movieClipInstanceName.variableName

That is, we refer to a variable on another timeline using the name of the clip that contains the variable, followed by a dot, then the variable name itself. In our earlier scenario, for example, from the main timeline we would refer to the variable x in the square clip as:

square.x

Again, from the main timeline, we refer to the variable y in the circle clip as:

circle.y

We can use these references from our main movie timeline to assign and retrieve variables in square like this:

square.z = 5;       // Assign 5 to z in square
var mainZ;          // Create mainZ on the main timeline
mainZ = square.z;   // Assign mainZ the value of z in square

However, with just the clip.variable syntax alone, we can't refer to variables in square from our circle clip. If we were to put a reference to square.x on a frame in circle, the interpreter would try to find a clip called square inside of circle, but square lives on the main timeline. So, we need a mechanism that lets us refer to the timeline that contains the square clip (in this case, the main timeline) from the circle clip. That mechanism comes in the form of two special properties: _root and _ parent.

2.5.6.1. The _root and _ parent properties

The _root property is a direct reference to the main timeline of a movie. From any depth of nesting in a movie clip structure, we can always address variables on the main movie timeline using _root, like this:

_root.mainZ       // Access the variable mainZ on the main timeline
_root.firstName   // Access the variable firstName on the main timeline

We can even combine a reference to _root with references to movie clip instances, drilling down the nested structure of a movie in the process. For example, we can address the variable x inside the clip square that resides on the main movie timeline, as:

_root.square.x

That reference works from anywhere in our movie, no matter what the depth of clip nesting, because the reference starts at our main movie timeline, _root. Here's another nested example showing how to access the variable area in the instance triangle that resides on the timeline of the instance shapes:

_root.shapes.triangle.area

Any reference to a variable that starts with the _root keyword is called an absolute reference because it describes the location of our variable in relation to a fixed, immutable point in our movie: the main timeline.

There are times, however, when we want to refer to variables on other timelines without referring to the main timeline of a movie. To do so, we use the _ parent property, which refers to the timeline upon which the current movie clip instance resides. For example, from code attached to a frame of the clip square, we can refer to variables on the timeline that contains square using this syntax:

_ parent.myVariable

References that start with the keyword _ parent are called relative references because they are resolved relative to the location of the clip in which they occur.

Returning to our earlier example, suppose we have a variable, size, defined on the main timeline of a movie. We place a clip instance named shapes on our main movie timeline, and on the shapes timeline we define the variable color. Also on the shapes timeline, we place a clip named triangle, as shown in Figure 2-1.

Figure 2-1

Figure 2-1. A sample movie clip hierarchy

To display the value of the variable color (which is in the shapes clip) from code attached to the timeline of triangle, we could use an absolute reference starting at the main timeline, like this:

trace(_root.shapes.color);

But that ties our code to the main movie timeline. To make our code more flexible, we could instead use the _ parent property to create a relative reference, like this:

trace(_ parent.color);

Our first approach (using _root) works from a top-down perspective; it starts at the main timeline and descends through the movie clip hierarchy until it reaches the color variable. The second approach (using _ parent) works from a bottom-up perspective; it starts with the clip that contains the trace( ) statement (the triangle clip), then ascends one level up the clip structure where it finds the color variable.

We can use _ parent twice in a row to ascend the hierarchy of clips and access our size variable on the main timeline. Here we attach some code to triangle that refers to size on the main movie timeline:

trace(_ parent._ parent.size);

Using the _ parent property twice in succession takes us up two levels, which in this context brings us to the main timeline of the movie.

Your approach to variable addressing will depend on what you want to happen when you place instances of a movie clip symbol on various timelines. In our triangle example, if we wanted our reference to color to always point to color as defined in the shapes clip, then we would use the _root syntax, which gives us a fixed reference to color in shapes. But if we wanted our reference to color to refer to a different color variable, depending on which timeline held a given triangle instance, we would use the _ parent syntax.

2.5.6.3. Flash 4 versus Flash 5 variable access syntax

The Flash 4-style slash-colon constructions such as /square:area have been superseded by Flash 5's dot syntax, a much more convenient way to refer to variables and timelines. The old syntax is deprecated and no longer recommended. Table 2-1 shows equivalencies between Flash 4 and Flash 5 syntax when addressing variables. See Appendix C, "Backward Compatibility", for other syntactical differences.

Table 2-1. Flash 4 Versus Flash 5 Variable Addressing Syntax

Flash 4 Syntax

Flash 5 Syntax

Refers to . . .

/
_root

Movie's main timeline

/:x
_root.x

Variable x on movie's main timeline

/clip1:x
_root.clip1.x

Variable x in instance clip1 on movie's main timeline

/clip1/clip2:x
_root.clip1.clip2.x

Variable x in instance clip2 within instance clip1 within the main movie timeline

../
_ parent

Timeline upon which the current clip resides (one level up from current clip timeline) [1]

../:x
_ parent.x

Variable x on timeline upon which the current clip resides (one level up from current clip timeline)

../../:x
_ parent._ parent.x

Variable x on timeline that contains the clip that contains the current clip (two levels up from current clip timeline)

clip1:x
clip1.x

Variable x in instance clip1, where clip1 resides on the current timeline

clip1/clip2:x
clip1.clip2.x

Variable x in instance clip2, where clip2 resides within clip1, which, in turn, resides on current timeline

_level1:x
_level1.x

Variable x on the main timeline of a movie loaded onto level 1

_level2:x
_level2.x

Variable x on the main timeline of a movie loaded onto level 2

[1] The "current clip timeline" is the timeline that contains the code with the variable reference.

2.5.7. Movie Clip Variable Life Span

Earlier, we said that the scope of a variable answers two questions: (a) how long does the variable exist? and (b) from where in our code can we set or retrieve the variable's value? For movie clip variables, we now know the factors involved in answering the second question. But we skipped answering the first question. Let's return to it now with one final variable-coding scenario.

2.5.8. Local Variables

Movie clip variables are scoped to movie clips and persist as long as the movie clip on which they are defined exists. Sometimes, that's longer than we need them to live. For situations in which we need a variable only temporarily, ActionScript offers variables with local scope (i.e., local variables), which live for a much shorter time than normal movie clip variables.

Local variables are used in functions and older Flash 4-style subroutines. If you haven't worked with functions or subroutines before, you can skip the rest of this section and come back to it once you've read Chapter 9, "Functions".

Functions often employ variables that are not needed outside the function. For example, suppose we have a function that displays all of the elements of a specified array:

function displayElements(theArray) {
   var counter = 0;
   while(counter < theArray.length) {
      trace("Element " + counter + ": " + theArray[counter]);
      counter++;
   }
}

The counter variable is required to display the array but has no use thereafter. We could leave it defined on the timeline, but that's bad form for two reasons: (a) if counter persists, it takes up memory during the rest of our movie; and (b) if counter is accessible outside our function, it may conflict with other variables named counter. We would, therefore, like counter to die after the displayElements( ) function has finished.

To cause counter to be automatically deleted at the end of our function, we define it as a local variable. Unlike movie clip variables, local variables are removed from memory (deallocated ) automatically by the interpreter when the function that defines them finishes.

To specify that a variable should be local, declare it with the var keyword from inside your function, as in the preceding displayElements( ) example.

Take heed though; when placed outside of a function, the var statement creates a normal timeline variable, not a local variable. As shown in Example 2-4, the location of the var statement makes all the difference.

Variables within functions need not be local. We can create or change a movie clip variable from inside a function by omitting the var keyword. If we do not use the var keyword, but instead simply assign a value to a variable, Flash treats that variable as a nonlocal variable under some conditions. Consider this variable assignment inside a function:

function setHeight( ){
   height = 10;
}

The effect of the statement height = 10; depends on whether height is a local variable or movie clip variable. If height is a previously declared local variable (which it is not in the example at hand), the statement height = 10; simply modifies the local variable's value. If there is no local variable named height, as is the case here, the interpreter creates a movie clip (nonlocal) variable named height and sets its value to 10. As a nonlocal variable, height persists even after the function finishes.

Example 2-4 demonstrates local and nonlocal variable usage.

Example 2-4. Local and Nonlocal Variables

var x = 5;                         // New nonlocal variable, x, is now 5
function variableDemo( ){
   x = 10;                         // Nonlocal variable, x, is now 10
   y = 20;                         // New nonlocal variable, y, is now 20
   var z = 30;                     // New local variable, z, is now 30
   trace(x + "," + y + "," + z);   // Send variable values to Output window
}
variableDemo( );   // Call our function. Displays: 10,20,30
trace(x);         // Displays: 10 (reassignment in our function was permanent)
trace(y);         // Displays: 20 (nonlocal variable, y, still exists)
trace(z);         // Displays nothing (local variable, z, has expired)

Note that it is possible (though confusing and ill-advised) to have both a local and a nonlocal variable that share the same name within a script but have different scopes. Example 2-5 shows such a case.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.