ActionScript 3.0

The common language of Flex 2 applications is ActionScript 3.0. You can't use any older versions of ActionScript, nor is it possible to create a functional application without at least some ActionScript 3.0. Additionally, we will soon see that MXML and AS3 are fundamentally related.

ActionScript's third incarnation is a mature language, as well as being substantially different from ActionScript 2. This chapter will rapidly cover all the fundamental aspects of ActionScript 3.0, but is by no means a full course. For more instruction, there is a list of useful further reading at the bottom of this Short Cut.

Where Are You Coming From?

Readers who understand ActionScript 2 should be comfortable transitioning to ActionScript 3.0. The following chapter specifically addresses new concepts since AS2, so read on!

Readers versed in C# or Java should find themselves at home with AS3 in short time, but should note a few differences in syntax and features. In any case, this chapter assumes, at minimum, basic knowledge of object-oriented programming.

Main Features

ActionScript is an ECMAScript language; ActionScript 3.0 implements the draft of ECMAScript (ECMA-262) Edition 4. This means two things: one, its true name is ridiculous and you don't have to remember it, and two, it is a draft, so there may be incremental changes in the future. Ecma International is an international standards organization that oversees ECMAScript and other technological standards. JavaScript is another implementation of ECMAScript, so ActionScript 3.0 will more than likely be identical to JavaScript when browsers implement Edition 4 of ECMAScript!

ActionScript 3.0 is a true object-oriented language, in that all types, including base types, are classes. Even a literal like 5 may have Number methods called directly on it. AS3 supports single inheritance: each class can extend only one other class.

The prototypal nature of earlier editions of ECMAScript is being slowly paved over in favor classical usage. Some parts of AS3 allow you to use it as a prototypal language, but this ability is rarely used and is not covered here. The virtual machine is tooled to work best when you program classically.

AS3 is also a functional language. Functions are objects—first class citizens—and can be stored and passed around. Lambda (or anonymous) functions are supported. Furthermore, the Array class acts as a list and supports many common list operations from functional programming.

ActionScript 3.0 supports both dynamically and statically typed variables. Dynamically typed, or "untyped" variables are able to change their type at runtime, and can use type inference to mutate type based on the value you assign to them. AS3 introduces the type * to denote an untyped variable. The compiler type-checks all typed variables and sealed classes, so using statically typed variables helps the compiler ensure the correctness of your programs. Classes are by default sealed: you cannot add properties or methods to classes at runtime. However, dynamic classes remain possible by using the dynamic keyword.

ActionScript 3.0 has a native event model. Unlike previous versions of ActionScript in which you had to choose an event framework, and you might see several different event handling schemes at work at the same time, AS3 provides a flexible multi-phase event model. The model is based on DOM Level 3, a W3C standard.

Runtime error handling is made easier by AS3's greatly improved use of exceptions. Many errors that were silent in previous versions of ActionScript now throw exceptions, easing debugging and allowing for more comprehensive fallback strategies.

AVM2

Behind much of the power of ActionScript 3.0 is a completely new virtual machine, the ActionScript Virtual Machine 2 (AVM2).

The virtual machine is what enables one SWF to run on a Mac, a PC, Linux, or a Pocket PC. AS3 code is compiled into bytecode, which are low-level instructions. The virtual machine inside Flash Player runs this bytecode. Classically, source code has been compiled into instructions for your CPU, but the result is that that program will run only on computers with the same CPU. Many modern languages have taken to using virtual machines to execute the same bytecodes, such as Java's JRE and .Net's CLR. Because your machine has to run a virtual machine inside of it, translating the instructions for the VM into instructions that your CPU can run, bytecode-interpreted languages can be slower than native programs, but they gain interoperability, safety, and flexibility.

Because the Flash Player must continue to be able to play older SWFs, Flash Player 9 actually contains two whole interpreters in it: AVM1 and AVM2. Whenever you use any ActionScript 3.0 in a SWF, it will run inside AVM2: this is the case for all Flex 2 applications. The AVM2 is new from the ground up, created with performance in mind, and its speed and stability make Flex 2 possible.

AVM2, and by association AS3, handles classes very differently from previous versions of ActionScript. ActionScript classes began as prototypal objects: in ActionScript 1 and in JavaScript, you can create "classes" by adding methods and variables to a prototype object that exists in memory. Inheritance was handled by copying the superclass's prototype and adding methods and properties, thus extending it and creating a prototype chain. In ActionScript 2, you could write classes in a familiar structure with a class block, but it was syntactic sugar: the ActionScript 2 compiler just converted these to prototype objects for you. Prototypal classes, however, have some glaring problems. Classes can be modified at runtime. Methods and variables can be referred to without being declared, or conversely can be overwritten at runtime. Perhaps most importantly, every method or property requested from a class instance would start the AVM on a wild hunt for that resource, looking in a hashtable in the object, then its prototype, its superclass's prototype, all the way up the inheritance chain!

The new virtual machine strikes a balance, allowing you to use the prototype object, but also flattening your classes. In the AVM2, all classes are stored in memory as a word-aligned structure, which means two things: class instances take up far less memory, and that looking up methods and properties is a direct operation. I have to mention all this because of one important implication. Using statically typed variables doesn't just check your work—it optimizes your program.

The AVM2 also gets a huge speed boost by using just-in-time compilation (JIT). Interpreting bytecode can be very slow compared to running instructions directly on your CPU. Just-in-time compilation will profile your application as it runs, discovering sections of code that run frequently, and further compile those into native code, all while your application is running. JIT, like compiler optimization, is a greatly behind-the-scenes process that you unfortunately can't play with, but its effects should have a terrific impact. For example, Java's improvements in JIT over the years have completely transformed an initially negative perception of its speed.

The AVM2 provides a garbage collection facility, so AS3 is a fully memory-managed language. When references pass out of scope and no (strong) references to them remain, they are later freed from memory. Like Java, new and delete are the primary means to manage your application's memory. However, the delete keyword is very limited in AS3 and setting references to null to allow objects to be collected is more common. ActionScript 3.0 lets you write constructors, but no destructors. The AVM2 uses a mark-and-sweep algorithm to perform garbage collection.

E4X

A welcome new feature to the core AS3 language is the inclusion of XML as a native data type with literals and intuitive operators. This feature is called ECMAScript for XML (E4X), and is another Ecma International standard with the less memorable full name ECMA-357. Not only does this make XML faster and easier to use than before, but it also makes XML a viable type for internally storing and manipulating information.

The new XML class is accompanied by a very useful class named XMLList. An XMLList relaxes one key requirement of well-formed XML: the single root node. It also is the typical return type for any filtering done using E4X methods and contains useful methods to manipulate its contents. You will find using an XMLList to store arbitrary chunks of XML data extremely convenient. It is also worth noting that the XML class from ActionScript 2 still exists as the class XMLDocument, making it easier to port legacy code.

Below is an example that just begins to show the things you can do with E4X.

//Just type out XML inline! No need for the <?xml version="1.0"?> prolog.
var roster:XML = <root>
       <person name="Ezra" skill="flash"/>
       <person name="Joey" skill="flex"/>
       <person name="Danny" skill="flash"/>
       <person name="Mims" skill="flex">
              <title>Minister of moustaches.</title>
       </person>
       <person name="Geoff" skill="javascript"/>
       <person name="Paul" skill="flash"/>
       <person name="Robert" skill="flash"/>
       <person name="Roger" skill="flex">
              <title>Your humble author.</title>
       </person>
</root>;

//You can be part of the team now! (Add a new child)
roster.appendChild(<person name="DearReader" skill="learning"/>);

//Who's first in line? (Find the name attribute of the first person tag)
trace(roster.person[0].@name); //Ezra

//Find out what Roger's supposed to be doing here.
//(The contents of the title node in the person tag whose name attribute is Roger)
trace(roster.person.(@name == "Roger").title); //Your humble author.

//Let's see how many Flexperts there are.
//(The length of the XMLList made of person tags whose skill attribute is flex)
trace(roster.person.(@skill == "flex").length()); //3

//You can save this line for the end of the book.
//(Store a reference to the person tag with a name attribute of DearReader)
//(Set the skill attribute on that person tag)
var you:XMLList = roster.person.(@name == "DearReader");
you.@skill = "flex";

//New Flexpert Appeared!
//(The length of the XMLList made of person tags whose skill attribute is flex)
trace(roster.person.(@skill == "flex").length()); //4

This example is a small part of what's possible with E4X. You can build complex searches by constructing a dot-separated query path. You can select children by inserting the name of the child node into a dot path (roster.person.title), and you can positionally select nodes with array-access-style bracket notation (roster.person[0]). You can navigate into attributes with the at (@) symbol, and you can select nodes which match arbitrary conditions (not just equality) within your path. The XMLList class provides more axis selectors than shown in this example, paralleling the abilities of XPath.

As you work with XML data in Flex 2, you can check the documentation and resources listed at the end of this Short Cut to learn more about E4X.

Regular Expressions

Another extremely useful and long-awaited language feature in AS3 is regular expressions. These objects make intricate string parsing a snap. There are a plethora of books and articles on this topic such as Mastering Regular Expressions, 2nd Edition by Jeffrey Friedl (O'Reilly). AS3 supports regular expressions as both literals—denoted by an expression surrounded by backslashes (/hello/)—and as instances of the class RegExp. Besides being able to run RegExp objects on Strings by passing them as arguments to RegExp instance methods, several String methods have been upgraded to accept regular expressions as arguments. Here is an example of how regular expressions might be used in ActionScript 3.0.

var str:String = "Rub a dub dub, three men in a tub. And who do you think they be?";
//look in the string for anything with a letter followed by "ub"
str.match(/wub/g); //Rub,dub,dub,tub
//make a regular expression which matches "dub dub"
var re:RegExp = new RegExp("dub dub");
//test the string for existence of the pattern
re.test(str); //true
//replace the pattern with our text
str.replace(re, "glub glub"); //Rub a glub glub, three men in a tub...
//look for all 3 letter words
//note that replace() returned the string but did not destructively modify it
str.match(/w{3}/g); //Rub,dub,dub,men,tub,And,who,you
//find the position of the first "a" character
str.search(/a/); //4

Note that regular expression literals in AS3 are only used to declare regular expressions, not to execute them, so you won't see constructs like m/fnord/ (which would search for the pattern "fnord" in many programming languages).

Display List

Flash developers, rejoice! The Flash Player API for managing visual elements (like MovieClip) has been completely redone. Whether or not you will be using Flash 9, it's important to understand this because Flex 2 uses the same paradigm. The new model is based on a display list.

Each visual element that may have children has a display list. You can think of it as a list because that's how you manage it, and because that's how depths are assigned. Only elements added to a display list get rendered when necessary. The list is rendered from the back to the front, and things on the front of the list are rendered on top of those in the back of the list.

In addition to how they are managed, the classes that represent visual elements themselves have been organized and built out. In SWFs published for Flash Player 9, everything visible on screen is in a display list and accessible to code, even static text fields and simple shapes. All display objects extend the abstract base class DisplayObject, and objects that can themselves contain other display objects also extend DisplayObjectContainer. Following are the most notable display objects that are available in AS3.

flash.display.MovieClip

The MovieClip class is very similar to its counterpart from previous versions of ActionScript: a visual element with an independent timeline that can contain any other display objects. Note that all of the properties that were once prefixed with an underscore, such as _alpha and _rotation, have dropped the underscore to become alpha and rotation. Note also that the class has moved from the top level into the flash.display package.

flash.display.Sprite

Like a MovieClip, a Sprite can contain any kind of display object, and can be transformed with the same properties. Sprites, however, don't have timelines, and therefore are more efficient, especially in large numbers. For many developers, Sprites will handily replace MovieClips as the default building block.

flash.display.Loader

Loaders are used to contain content that is loaded at runtime, both SWFs and graphics. They replace both the MovieClipLoader class and the loadMovie() method from previous versions of ActionScript.

These and the other display objects are essential for applications using the Flash Player 9 display list. While using Flex 2, you will have access to the Flash Player API and these classes, but keep in mind you will most likely use Flex 2 components instead of these classes.

The ways you can manipulate display objects are completely different from previous versions of ActionScript as well. Forget all you know about createEmptyMovieClip, attachMovie, and swapDepths, and concentrate on display objects and display lists:

var box:Sprite = new Sprite();
addChild(box);
var jack:Sprite = new Sprite();
box.addChild(jack);

The first line creates a new empty Sprite. The second line will add the box to our display list, making it visible. Next, we create another new Sprite, this time a jack, and put the jack in the box.

Assets are handled as subclasses. If you actually had an image associated with the jack, you could name it Jack, and Jack would be a subclass of Sprite. Now the Jack class is just a special kind of Sprite that has a particular appearance. This idea replaces linkage names and can be found in both Flex 2 and Flash 9.

Instead of using the _visible property from earlier versions of Flash, which often left the invisible clip taking up resources every frame, simply remove it from the display list that contains it. The display object is still there for your use (as long as you keep a reference to it), but no time will be spent rendering it or running its timeline.

box.removeChild(jack);
royalFlush.addChild(jack);

You can even re-parent objects, moving them into completely different containers. Here we take jack out of the box and instead use it to complete royalFlush. You win!

Core types

ActionScript 3.0 adds a few core types and continues to support all of the ones present in AS2. It is worth mentioning again that AS3 is a true object-oriented language and all of these types are classes. Core types inherited from previous versions of ActionScript include:

Number

A double-precision floating point number.

Date

A representation of a specific point in time.

String

A string, much like Java's String. There is no type for a single character.

Boolean

A Boolean value, true or false.

Array

An untyped (it can contain objects of mixed type) auto-sizing list.

Object

Anonymous object and the root class for all class hierarchies in AS3. Can add properties at runtime, making it useful as a dictionary that supports string keys.

Function

A function.

AS3 introduces a few new core types:

int

A 32-bit signed (two's complement) integer

uint

A 32-bit unsigned integer

XML

XML data

Class

A runtime representation of a class. Stores the class's static properties and methods. Class references can be used with the new operator to create instances of the class.

Namespace

A representation of a namespace.

Error

The base type for all exceptions.

Visibility

ActionScript 3.0 provides more granularity in setting the visibility of properties, methods and classes than previous versions of ActionScript. In addition, the meaning of some visibility modifiers has changed since ActionScript 2.

public

Used to declare classes, properties, methods, and namespaces that are accessible to any caller.

protected

Used only inside class definitions to declare properties, constants, methods, and namespaces that are available to the declaring class and any of its subclasses.

private

Used within class definitions to declare properties, constants, methods, and namespaces that are available only within the declaring class. More strict than its meaning in ActionScript 2.

internal

Used to declare classes, properties, methods, and namespaces that are accessible within the package they are declared in.

If you omit a visibility attribute on any declaration inside a class definition, AS3 will implicitly assign it the internal attribute.

Furthermore, AS3 enables you to create and use custom namespaces. Classes, properties, and methods declared in a custom namespace are visible to other code in the same namespace, code which has opened the namespace by using the use namespace directive, or by using the name qualifier operator (::) to specify the namespace the property is found in. You can use any valid identifier name for your namespace, and you may also bind it to a URI (Uniform Resource Identifier). When you declare a class, property, or method in a custom namespace you may not also use a predefined namespace like public or private.

Type Manipulation

ActionScript 3.0 provides you with a set of tools to manipulate types safely and intelligently. The compiler type-checks your program and can catch many errors at compile-time when you use typed variables. The rules that are enforced are fairly straightforward. All typed parameters of a function call or subjects of an operator must be passed compatible types. In assignments, a variable (the left hand side) and the expression or value you assign to it (the right hand side) must be of compatible types. And an expression or value returned with the return keyword must match the return type of the function.

Furthermore, the AVM2 stores type information with all variables that are declared with a type. In previous versions of ActionScript, the compiler would check types at compile time, but all objects in the AVM1 were dynamically typed, so that you could mutate the type of variables at runtime by bypassing the compiler checks, for instance by referencing the variable through a lookup. The AVM2 can enforce type safety at runtime as well, and incompatible type assignments throw a TypeError exception. This is good news, because incompatible assignments that might otherwise silently fail—causing later errors and forcing you to investigate—are now immediately identifiable.

You may investigate the type of a value with the is operator. The is operator replaces the instanceof operator from ActionScript 2 and provides the same functionality as Java's instanceof operator. The expression:

a is B

where a is an object of type A and B is a type will return true if B can be found by following the type hierarchy of A up, that is, towards Object. For example, a is B if:

  • A is the same class as B

  • A extends B

  • A implements B

  • A combination of the above, e.g. A's superclass's superclass implements B

Earlier I mentioned the idea of compatible types. A type is compatible with all types that are in the same type hierarchy but are more general. For instance, Dessert is more general than Cupcake, so you could refer to a particular Cupcake as a Dessert with no problem. ActionScript 3.0 lets you assign values to variables of more general types without hassle. So you could easily do

public function eatDessert(somethingTasty:Dessert):void
{
       trace("yum.. that's a good " + somethingTasty.toString());
}
var chocolateCupcake:Cupcake = Magnolia.getCupcake("chocolate");
eatDessert(chocolateCupcake); //chocolateCupcake is treated as a Dessert
trace(chocolateCupcake is Dessert); //true

This example passes a Cupcake to a function that expects a Dessert, but the types are compatible so the code is valid. Another situation where types are compatible is when AS3 knows how to convert one type into another. In certain situations, AS3 automatically performs this type coercion. For instance:

var coerce:String = "Party like it's " + 2099;

implicitly coerces the integer 2099 into a String which the + operator expects in a String context.

It is a desirable object-oriented programming practice to program to interfaces and not implementations. So if you type all of your variables as IEdible, how will you get a Cupcake back when you need one? Occasionally it is necessary to convert types toward the more specific, and AS3 allows you to do this with two kinds of explicit type conversion: a cast and a conditional cast.

Casting forces a variable of one type to be another type. To capture the result of this operation, you should assign it to a new variable of the desired type, for instance,

var cupcake:Cupcake = Cupcake(somethingTasty);

Java and C developers, take note that the parentheses appear around the expression rather than the type. If this type conversion is impossible, that is, if the object you are casting is not actually the type you request or compatible with the type you request, a TypeError is thrown. In this example, your somethingTasty, which is currently typed as a Dessert, must have originally been a Cupcake.

var cupcake:Dessert = new Cupcake(); //using a Cupcake as a Dessert, OK
var baklava:Dessert = new Baklava(); //using a Baklava as a Dessert, OK
Cupcake(cupcake).addSprinkles(); //OK because it started life as a Cupcake
Cupcake(baklava).addSprinkles(); //NOT OK! Baklava is not compatible with Cupcake

The as operator performs a conditional cast. If the requested type conversion is not possible, instead of throwing a TypeError, the expression merely returns null. This is similar to a dynamic_cast in C++ and the identical operator in C#. This is also more or less the behavior of casts in ActionScript 2. Unless you can check the result of a conditional cast, or you have previously verified that the types are compatible, you should use a normal cast instead. This way you can catch potential problems as exceptions. However, the as operator's special properties can make it useful to create creatively concise code, such as this example:

var cookie:Cookie;
for each (var dessert:Dessert in desserts)
{
       //use the as operator to frost all cookies in a dessert list
       //returns null if the cast fails, skipping the if block
       if (cookie = dessert as Cookie)
       {
              cookie.frost();
       }
}

It is also worth mentioning here how ActionScript 3.0 deals with initial values. If a variable does not have a value assigned to it, but has a specific type, its default value depends on its type. For example, an unassigned int has the value 0, an unassigned Number has the value NaN, and all complex types have a default value of null. Core types that have default values can't be assigned null or undefined. The value undefined still exists, but only represents an unassigned, untyped variable. In general, AS2 developers coming to AS3 can forget about the confusing differences between undefined and null, and stick to null.

Packages and Classes

Packages are a way to organize code and avoid name collisions. In ActionScript 2, you would place class files in a folder structure that defined their fully qualified class name. For example, the class com.partlyhuman.Banana would be defined in the file com/partlyhuman/Banana.as. In ActionScript 3.0, packages are more than file paths. You must use the package block to declare packages, and only code found inside package blocks is visible outside of a file. Packages are also used to control access, as you have seen with internal.

Classes are defined in a class block. To make your class visible outside the file it is written in, you must place it in the appropriate package block and declare it as public:

//in file com/partlyhuman/Banana.as
package com.partlyhuman
{
       public class Banana
       {
       }
}

Packages may contain not just classes, but functions, variables, namespaces, and even statements. However, a maximum of one item per file is allowed to be visible to the outside, and the file's name must mirror this item. Items declared inside a package block are allowed only two access specifiers: public and internal.

Typically, you will write files with a package block containing one public class or function. One exception is a common implementation of the Singleton pattern, which provides global access to a single instance and prevents instantiation of more than one instance. Because AS3 does not permit private constructors, the pattern requires an object to be passed to the constructor whose type is visible only inside the same file, so that code external to this class won't be able to provide the appropriate argument to the constructor, making it as good as private:

package com.partlyhuman
{
       public class SingletonDemonstration
       {
              private static var instance:SingletonDemonstration;
              public function SingletonDemonstration(enforcer:SingletonEnforcer)
              {
                     //initialization code
              }
              public static function getInstance():SingletonDemonstration
              {
                     if (instance == null)
                     {
                           instance = new SingletonDemonstration(new
SingletonEnforcer());
                     }
                     return instance;
              }
       }
}
class SingletonEnforcer {}

ActionScript 3.0 supports similar inheritance patterns to Java. Classes may extend one class and implement multiple interfaces.

public interface IPoppable
{
       function pop():void
}
public interface IInflatable
{
       function inflate():void
}
public class Balloon implements IPoppable, IInflatable
{
       public function Balloon()
       {
              //initialize the balloon
       }
       public function pop():void
       {
              //you must implement methods from all interfaces
              //methods found in interfaces are always public
       }
       public function inflate():void
       {
              //inflate
       }
}
public final class Blimp extends Balloon
{
       public function Blimp()
       {
              //call the superclass constructor
              super();
              //do more fun stuff
       }
       public function fly():void
       {
              //a blimp is like a balloon that can fly... or something.
       }
}

Here, a Balloon class is created that supports the operations defined in the interfaces IPoppable and IInflatable. These interfaces may only define methods, and you don't need to specify the visibility of the methods: they must all be implemented as public.

Abstract classes, or virtual or abstract methods, are not part of AS3. You can enforce abstractness at runtime, however, by throwing errors in your abstract class's constructor or your abstract method.

The above example also shows an example of a final class. Final classes may not be extended; they are the final class in their class hierarchy. This prevents people using your code from taking your hard work on the Blimp and using it for evil, creating MissileBlimps and LaserBlimps. In reality, this might be used for classes that are provided to use but should not be modified, for example flash.system.Security.

Classes may also be declared dynamic. When this keyword is not used, classes are sealed: their methods and properties are written in stone and may not be modified at runtime. With dynamic, you can access and create properties and methods on instances of that class at runtime. This can be useful to create simple wrappers of data, for example, storing arbitrary data in Object instances. Dynamic classes cannot benefit from some of the optimizations of the AVM2, so use them only when appropriate.

Methods and Properties

Let's add a little bit more to that Blimp class:

public final class Blimp extends Balloon
{
       private const TAKEOFF_PRESSURE:Number = 10000;
       private var currentPressure:Number;
       public function Blimp()
       {
              super();
              currentPressure = 100;
       }
       override public function pop():void
       {
              //abandon ship!
       }
       override public function inflate():void
       {
              //inflate the same way as a balloon, then add our own behavior
              super.inflate();
              if (currentPressure >= TAKEOFF_PRESSURE) fly();
       }
       public function fly():void
       {
              //go, go, majestic blimp!
       }
}

There are a few new features introduced in AS3 which are demonstrated here. ActionScript 3.0 includes constants, variables whose values may not be changed. The compiler will stop you if you try to make a second assignment to a constant, or from outside the class definition. The Blimp's inflate() method uses the constant TAKEOFF_PRESSURE to check if it's ready to take off. Constants are declared with the keyword const in place of var.

You might also note that the method pop() is marked override as well as public. ActionScript 3.0 allows you to write methods that also exist on the superclass, but you must assure the compiler that you are intentionally overwriting this method with the override keyword. The overriding method may also call the original implementation by calling the same method on the super object, a reference to the class's superclass. Also, the signature of the overriding method must completely match the signature of the overridden method. ActionScript 3.0 supports only one method with the same name, so this means you can't do overloading, where a method can perform differing operations based on its input. However, you can always use a variable argument list (as discussed below) to achieve this.

Static variables, or class variables, are allowed in ActionScript 3.0, identically to AS2. Static variables are declared with the static keyword. These variables belong to the class itself, so they will be the same across instances of the same class. This could be used in our Blimp to store properties that should be the same across all blimps, like the number of wheels on the landing gear.

ActionScript 3.0 supports implicit, as well as explicit, accessors. Explicit accessors are normal methods that retrieve or set values; for example, if the Blimp has setAltitude() and getAltitude() methods which manipulate the Blimp's internal altitude. Accessors provide an alternative to declaring public instance variables, and give your class the control to perform certain checks against the set value, or additional operations when those values are set. This is a good practice that you should follow to maintain encapsulation. Implicit accessors let client code maintain the illusion of setting a property directly on your class, while still allowing you to intercept control. Instead of:

public function setAltitude(newAltitude:Number):void {...}
public function getAltitude():Number {...}
myBlimp.setAltitude(10);

you could use implicit accessors by writing:

public function set altitude(newAltitude:Number):void {...}
public function get altitude():Number {...}
myBlimp.altitude = 10;

Finally, ActionScript 3.0 supports method closures or bound methods. A closure is a function that can refer to variables in its surrounding block, regardless of where it is called from. It's like packaging a function with its own scope. Many AS2 developers may be familiar with the code

var closure:Function = Delegate.create(this, doFoo);

which creates a closure. Any time you run closure(), doFoo()executes in the original scope you called Delegate.create() from. In AS3, all methods defined in a class are bound to that class without any extra work, so even if you execute those methods from an event handler or from a reference to the method passed as a Function, the methods can access their owner class's methods and properties.

Arguments

The ActionScript 3.0 compiler enforces that your function calls match the function's signatures. Generally, parameters must appear in the correct order, with compatible types, and without any parameters missing. However, ActionScript 3.0 adds some tools to relax these requirements and to add convenience as well as flexibility.

Default values are a new addition to ActionScript from the C++ world. You can make some parameters to your function optional by declaring default values for these arguments right in the argument list. For example, you might have a complex operation with lots of options:

function makeDagwood(layers:int, meat:String, cheese:String, bread:String,
mayo:Boolean, mustard:Boolean, lettuce:Boolean):Sandwich {...}

While you want users of your code to have full control of their sandwich, you want to keep their code concise and specify some reasonable defaults:

function makeDagwood(layers:int, meat:String, cheese:String, bread:String,
mayo:Boolean = true, mustard:Boolean = true, lettuce:Boolean = true):Sandwich {...}

Now if you're happy to have all the condiments on your sandwich, you can keep your function call simple:

makeDagwood(3, "Turkey", "Muenster", "Wheat"); //has all condiments by default
makeDagwood(3, "Roast Beef", "Swiss", "Rye", false, false, true); //no mayo or mustard

All parameters with default values must be placed at the end of the argument list, and will become optional to pass into the function.

You may also define functions that take variable numbers of arguments. The arguments array from ActionScript 2 still exists. Every Function object contains the arguments property, which is an array of all parameters passed to the function. However, ActionScript 3.0 requires you to specify your parameters well, so the ... keyword is provided. This allows you to require some parameters but allow many others after that.

function addSandwichRecipe(sandwichName:String, ... layers):void {...}

Inside addSandwichRecipe(), the layers array contains all the additional parameters passed to the function. You can use any valid identifier to store the additional parameters. A typical name for this array is rest, so you may hear the ... keyword referred to as the rest keyword. Because there is a normal argument before the rest keyword, this method requires a recipe name:

addSandwichRecipe("PB&J", bread, peanutButter, jelly, bread);
addSandwichRecipe("The English King", englishMuffin, peanutButter, banana, honey);
addSandwichRecipe("The Ultra Slim"); //This is valid! I guess this is an Air sandwich.

A final note about parameters for ActionScript 2 developers: to specify a function which requires zero parameters, use function foo(), not function foo(Void) as you would in AS2.

Events

ActionScript 3.0 provides you with a unified, built-in, and standards-based event framework to drive your application with user input and decouple your collaborating classes.

You can subscribe to events with the addEventListener() method. This method is defined on all classes that implement IEventDispatcher, which includes quite a lot of classes. The new event model replaces all callback methods from previous ActionScript versions. For instance, instead of defining the onClick() function on a button, we use the event model:

myButton.addEventListener(MouseEvent.CLICK, onButtonClicked);
function onButtonClicked(event:MouseEvent):void
{
       myButton.label = "Quit clicking me!";
       myButton.removeEventListener(MouseEvent.CLICK, onButtonClicked);
}

The first line sets up an event listener for single clicks on the button myButton. When the button is clicked, the method onButtonClicked() is invoked. Notice that when you register an event listener, the event handler method must accept an Event as its parameter. In this case, we know it's going to be a MouseEvent so we type the event as a MouseEvent, a subclass of Event.

One simple, but key improvement in the built-in events is AS3's usage of constants to define all event types. In this case, MouseEvent.CLICK represents an event type to listen for; but this event type is just a string. Somewhere in the MouseEvent class it says:

public static const CLICK:String = "click";

All across the new AS3 API, and especially in the event packages, you will find that magic strings are replaced by constants. When you use constants, the compiler can catch typos before they become bugs.

Back to our button example: you might also have noticed that the event handler, onButtonClicked(), refers to myButton instead of this. The function, even though it was invoked by a click on myButton, still executes in the scope of the code it was added to. ActionScript 3.0 creates a bound method for you whenever you call addEventListener(), binding the listener function to its owner and making writing event handlers more intuitive. Just write them like any other method, and refer to them without using Delegate.create(). The object that spawned the event will always be available to you through event.target.

The example also shows removing an event listener after modifying the label of the button. It's important to clean up your event listeners when they are no longer valid. If you forget to remove an event listener, the object won't be removed by the garbage collector and can sit around, using up space. These uncollected objects can pile up and gradually affect the performance of your application.

To avoid this effect, one kind of memory leak, ActionScript 3.0 allows you to attach an event listener with a weak reference, which allows the object to be deleted even if the event listener has not been explicitly removed. To enable a weak reference, simply pass true to the last parameter of addEventListener(), weakRef:

myButton.addEventListener(MouseEvent.CLICK, onButtonClicked, false, 0, true);

The ActionScript 3.0 event model is tied tightly into the display list. Events travel through three phases after they are triggered, giving you granular control over when and where to capture and react to them. These three phases are collectively called the event flow. Think of it as a trip your event takes through the display list, with an opportunity to intercept, examine, and maybe even stop it at any point along the way.

I think the event flow is something like the game Bubble Bobble, shown in Figure 2. In Bubble Bobble, you control a little dragon with the ability to blow bubbles straight ahead. If you're in line with an enemy and your bubble travels far enough to hit it, the enemy gets trapped in the bubble. Then the bubble, complete with helpless enemy, floats up to the top of the screen, waiting for you to pop it. If this game were the event flow, the bubble would be the event, the enemy would be the subject of that event, and the playing field would represent your opportunities to examine or interrupt the event.

Event bubbling is like Bubble Bobble: capture, target, and bubble phases

Figure 2. Event bubbling is like Bubble Bobble: capture, target, and bubble phases

Let's say the user clicks on a button. First, you blow a bubble, which makes its way towards the enemy. This is called the capture phase. In the Flash Player, the event is traveling down the hierarchy of display objects, from the root of the display list (the stage) to the button that was clicked. If you set up an event listener for the capture phase on any object that is a parent of the button, you can respond to that click before the button does, even though it is eventually destined for the button.

Next, the bubble envelops the enemy. This is the target phase. From here on, the target of the event object is set to that button, and from here on the enemy is stuck inside that bubble. If you subscribed directly to the button without specifying the capture phase, this is when you'll receive the event. This is the most straightforward way of dealing with events, and the most familiar for ActionScript 2 developers.

Finally, the bubble rises to the top of the level in the bubbling phase. With the correct target still set inside the event, the event is passed back up to the root of the display tree, so that the parents of the button have a chance to examine or use the event. This bubbling happens automatically as long as your event's bubbles property is true. The bubbling phase is useful when you want to deliver a custom event to the outside of a complex subsystem. Say the alarm event originates in a vibrating quartz crystal inside your watch. Without doing any extra work, or breaking the encapsulation of your watch by looking directly at the quartz, you can be notified that it's time for a snack if you subscribe to your watch; the alarm event bubbles out from the quartz crystal to the watch.

During any of these phases, many events may be canceled with the stopPropogation() and stopImmediatePropogation() methods. This is like your dragon character popping the bubble with its spiny back to make sure other players aren't able to reach it. The event must be declared cancelable, though, so there are some tough bubbles that you can't pop.

Reflection

Yes, Virginia, ActionScript 3.0 provides features to perform reflection! Reflection is the ability for a program to be aware of and modify its behavior at runtime, specifically by discovering and creating objects and executable constructs.

Previous versions of ActionScript allowed you to perform some rudimentary reflection by listing available methods of a class with a for..in loop, and by referencing properties and methods of classes by name with bracket notation such as obj["method"](). In ActionScript 3.0, you may still access properties dynamically with bracket notation. However, a simple loop will only iterate over dynamically added properties.

This kind of reflection, introspection, provides information about types and objects at runtime. AS3 provides much better tools for introspection. The function flash.utils.describeType(classOrClassInstance) provides ridiculously detailed information in XML on the class you pass it, including its full type hierarchy, methods and parameters with types, properties, and accessors. The mx.utils.ObjectUtil class also provides a getClassInfo() function which does much the same.

Beyond discovering information about a class whose reference you have, AS3 also lets you look up classes, namespaces, and functions, directly from strings. This can be extremely powerful, for example, to serialize application state and class dependencies into text, and to reconstruct the classes from text. Here, we store the name of one display object class and create another directly from its class name:

import flash.utils.*;
var mySprite:Sprite = new Sprite();
var className:String = getQualifiedClassName(mySprite);
trace(className); //flash.display.Sprite

Alert; //force this class to compile in so that runtime code can use it.
try
{
       var ClassReference:Class = getDefinitionByName("mx.controls.Alert") as Class;
       addChild(new ClassReference());
} catch (error:ReferenceError) {
       trace("We couldn't look up that class");
}

Notice how we're able to store Classes as objects, and we can actually instantiate them with new.

Recap

ActionScript 3.0 introduces a slew of new capabilities and a completely reengineered API, all of which make Flex 2 possible. With this foundation, you can start learning how to take advantage of the Flex framework and MXML.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.47.25