Clases

Una clase es una representación abstracta de un objeto. Una clase almacena información sobre los tipos de datos que un objeto puede contener y los comportamientos que un objeto puede exhibir. La utilidad de esta abstracción puede no ser apreciable al escribir scripts sencillos que sólo contienen unos pocos objetos que interactúan entre sí. Sin embargo, conforme crece el ámbito de un programa aumenta el número de objetos que deben administrarse. En este caso, las clases permiten controlar mejor el modo en que se crean los objetos y la forma en que interaccionan unos con otros.

Con ActionScript 1.0 los programadores podían utilizar objetos Function para crear construcciones similares a las clases. ActionScript 2.0 añadió formalmente la compatibilidad con las clases con palabras clave como class y extends. En ActionScript 3.0 no sólo se mantienen las palabras clave introducidas en ActionScript 2.0, sino que también se han añadido algunas capacidades nuevas. Por ejemplo, ActionScript 3.0 incluye un control de acceso mejorado con los atributos protected e internal. También proporciona un mejor control de la herencia con las palabras clave final y override.

A los desarrolladores con experiencia en la creación de clases con lenguajes de programación como Java, C++ o C#, ActionScript les resultará familiar. ActionScript comparte muchas de las mismas palabras clave y nombres de atributo como, por ejemplo, class, extends y public.

Nota: en la documentación de Adobe ActionScript, el término propiedad designa cualquier miembro de un objeto o una clase, incluidas variables, constantes y métodos. Por otra parte, aunque los términos class y static se suelen utilizar como sinónimos, aquí tienen un significado diferente. Por ejemplo, la frase “propiedades de clase” hace referencia a todos los miembros de una clase, no únicamente a los miembros estáticos.

Definiciones de clase

En las definiciones de clase de ActionScript 3.0 se utiliza una sintaxis similar a la utilizada en las definiciones de clase de ActionScript 2.0. La sintaxis correcta de una definición de clase requiere la palabra clave class seguida del nombre de la clase. El cuerpo de la clase, que se escribe entre llaves ({}), sigue al nombre de la clase. Por ejemplo, el código siguiente crea una clase denominada Shape que contiene una variable denominada visible:

public class Shape 
{ 
    var visible:Boolean = true; 
}

Un cambio de sintaxis importante afecta a las definiciones de clase que están dentro de un paquete. En ActionScript 2.0, si una clase estaba dentro de un paquete, había que incluir el nombre de paquete en la declaración de la clase. En ActionScript 3.0 se incluye la sentencia package y hay que incluir el nombre del paquete en la declaración del paquete, no en la declaración de clase. Por ejemplo, las siguientes declaraciones de clase muestran la manera de definir la clase BitmapData, que forma parte del paquete flash.display, en ActionScript 2.0 y en ActionScript 3.0:

// ActionScript 2.0 
class flash.display.BitmapData {} 
 
// ActionScript 3.0 
package flash.display 
{ 
    public class BitmapData {} 
}

Atributos de clase

ActionScript 3.0 permite modificar las definiciones de clase mediante uno de los cuatro atributos siguientes:

Atributo

Definición

dynamic

Permite añadir propiedades a instancias en tiempo de ejecución.

final

No debe ser ampliada por otra clase.

internal (valor predeterminado)

Visible para referencias dentro del paquete actual.

public

Visible para referencias en todas partes.

Todos estos atributos, salvo internal, deben ser incluidos explícitamente para obtener el comportamiento asociado. Por ejemplo, si no se incluye el atributo dynamic al definir una clase, no se podrá añadir propiedades a una instancia de clase en tiempo de ejecución. Un atributo se asigna explícitamente colocándolo al principio de la definición de clase, como se muestra en el código siguiente:

dynamic class Shape {}

Hay que tener en cuenta que la lista no incluye un atributo denominado abstract. Las clases abstractas no se admiten en ActionScript 3.0. También se debe tener en cuenta que la lista no incluye atributos denominados private y protected. Estos atributos sólo tienen significado dentro de una definición de clase y no se pueden aplicar a las mismas clases. Si no se desea que una clase sea visible públicamente fuera de un paquete, debe colocarse la clase dentro de un paquete y marcarse con el atributo internal. Como alternativa, se pueden omitir los atributos internal y public y el compilador añadirá automáticamente el atributo internal. También se puede definir una clase para que sólo se pueda ver en el archivo de origen en el que se define. Sitúe la clase en la parte inferior del archivo de origen, bajo la llave de cierre de la definición del paquete.

Cuerpo de la clase

El cuerpo de la clase se escribe entre llaves. Define las variables, constantes y métodos de la clase. En el siguiente ejemplo se muestra la declaración para la clase Accessibility en ActionScript 3.0:

public final class Accessibility 
{ 
    public static function get active():Boolean; 
    public static function updateProperties():void; 
}

También se puede definir un espacio de nombres dentro de un cuerpo de clase. En el siguiente ejemplo se muestra cómo se puede definir un espacio de nombres en el cuerpo de una clase y utilizarse como atributo de un método en dicha clase:

public class SampleClass 
{ 
    public namespace sampleNamespace; 
    sampleNamespace function doSomething():void; 
}

ActionScript 3.0 permite incluir en el cuerpo de una clase no sólo definiciones, sino también sentencias. Las sentencias que están dentro de un cuerpo de clase pero fuera de una definición de método se ejecutan una sola vez. Esta ejecución se produce cuando se encuentra por primera vez la definición de la clase y se crea el objeto de clase asociado. En el ejemplo siguiente se incluye una llamada a una función externa, hello(), y una sentencia trace que emite un mensaje de confirmación cuando se define la clase:

function hello():String 
{ 
    trace("hola"); 
} 
class SampleClass 
{ 
    hello(); 
    trace("class created"); 
} 
// output when class is created 
hola 
class created

En ActionScript 3.0 se permite definir en un mismo cuerpo de clase una propiedad estática y una propiedad de instancia con el mismo nombre. Por ejemplo, el código siguiente declara una variable estática denominada message y una variable de instancia con el mismo nombre:

class StaticTest 
{ 
    static var message:String = "static variable"; 
    var message:String = "instance variable"; 
} 
// In your script 
var myST:StaticTest = new StaticTest(); 
trace(StaticTest.message); // output: static variable 
trace(myST.message); // output: instance variable

Atributos de propiedad de clase

En las descripciones del modelo de objetos de ActionScript, el término propiedad significa cualquier cosa que pueda ser un miembro de una clase, incluidas variables, constantes y métodos. Sin embargo, en Adobe ActionScript 3.0 Reference for the Adobe Flash Platform, el término se aplica a un concepto menos amplio. En ese contexto la propiedad del término sólo incluye miembros de clase que son variables o se definen mediante un método captador o definidor. En ActionScript 3.0 hay un conjunto de atributos que se pueden utilizar con cualquier propiedad de una clase. En la tabla siguiente se muestra este conjunto de atributos.

Atributo

Definición

internal (valor predeterminado)

Visible para referencias dentro del mismo paquete.

private

Visible para referencias dentro de la misma clase.

protected

Visible para referencias en la misma clase y en clases derivadas.

public

Visible para referencias en todas partes.

static

Especifica que una propiedad pertenece a la clase en lugar de a las instancias de la clase.

UserDefinedNamespace

Nombre de espacio de nombres personalizado definido por el usuario.

Atributos del espacio de nombres de control de acceso

ActionScript 3.0 proporciona cuatro atributos especiales que controlan el acceso a las propiedades definidas dentro de una clase: public, private, protected e internal.

El atributo public hace que una propiedad esté visible en cualquier parte del script. Por ejemplo, para hacer que un método esté disponible para el código fuera de su paquete, hay que declarar el método con el atributo public. Esto se cumple para cualquier propiedad, independientemente de que se declare con la palabra clave var, const o function.

El atributo private hace que una propiedad sólo esté visible para los orígenes de llamada de la clase en la que se define la propiedad. Este comportamiento difiere del comportamiento del atributo private en ActionScript 2.0, que permitía a una subclase tener acceso a una propiedad privada de una superclase. Otro cambio importante de comportamiento está relacionado con el acceso en tiempo de ejecución. En ActionScript 2.0, la palabra clave private sólo prohibía el acceso en tiempo de compilación y se podía evitar fácilmente en tiempo de ejecución. Esto ya no se cumple en ActionScript 3.0. Las propiedades marcadas como private no están disponibles en tiempo de compilación ni en tiempo de ejecución.

Por ejemplo, el código siguiente crea una clase simple denominada PrivateExample con una variable privada y después intenta acceder a la variable privada desde fuera de la clase.

class PrivateExample 
{ 
    private var privVar:String = "private variable"; 
} 
 
var myExample:PrivateExample = new PrivateExample(); 
trace(myExample.privVar);// compile-time error in strict mode 
trace(myExample["privVar"]); // ActionScript 2.0 allows access, but in ActionScript 3.0, this is a run-time error. 

En ActionScript 3.0, un intento de acceder a una propiedad privada mediante el operador punto (myExample.privVar) provoca un error de tiempo de compilación si se utiliza el modo estricto. De lo contrario, el error se notifica en tiempo de ejecución, de la misma que manera que al usar el operador de acceso a una propiedad (myExample["privVar"]).

En la tabla siguiente se resumen los resultados de intentar acceder a una propiedad privada que pertenece a una clase cerrada (no dinámica):

 

Modo estricto

Modo estándar

operador punto (.)

error en tiempo de compilación

error en tiempo de ejecución

operador corchete ([])

error en tiempo de ejecución

error en tiempo de ejecución

En clases declaradas con el atributo dynamic, los intentos de acceder a una variable privada no provocarán un error en tiempo de ejecución. En su lugar, la variable no está visible, por lo que se devuelve el valor undefined. No obstante, se producirá un error en tiempo de compilación si se utiliza el operador punto en modo estricto. El ejemplo siguiente es igual que el anterior, con la diferencia de que la clase PrivateExample se declara como una clase dinámica:

dynamic class PrivateExample 
{ 
    private var privVar:String = "private variable"; 
} 
 
var myExample:PrivateExample = new PrivateExample(); 
trace(myExample.privVar);// compile-time error in strict mode 
trace(myExample["privVar"]); // output: undefined

Las clases dinámicas generalmente devuelven el valor undefined en lugar de generar un error cuando código externo a una clase intenta acceder a una propiedad privada. En la tabla siguiente se muestra que sólo se genera un error cuando se utiliza el operador punto para acceder a una propiedad privada en modo estricto:

 

Modo estricto

Modo estándar

operador punto (.)

error en tiempo de compilación

undefined

operador corchete ([])

undefined

undefined

El atributo protected, que es una de las novedades de ActionScript 3.0, hace que una propiedad esté visible para los orígenes de llamada en su propia clase o en una subclase. Es decir, una propiedad protegida está disponible en su propia clase o para clases de nivel inferior en la jerarquía de herencia. Esto se cumple tanto si la subclase está en el mismo paquete como si está en un paquete diferente.

Para los usuarios familiarizados con ActionScript 2.0, esta funcionalidad es similar al atributo private en ActionScript 2.0. El atributo protected de ActionScript 3.0 también es similar al atributo protected en Java. Difiere en que la versión de Java también permite acceder a quien realiza la llamada en el mismo paquete. El atributo protected resulta útil cuando se tiene una variable o método requerido por las subclases que se desea ocultar del código que esté fuera de la cadena de herencia.

El atributo internal, que es una de las novedades de ActionScript 3.0, hace que una propiedad esté visible para los orígenes de llamada en su propio paquete. Es el atributo predeterminado para el código de un paquete y se aplica a cualquier propiedad que no tenga ninguno de los siguientes atributos:

  • public

  • private

  • protected

  • un espacio de nombres definido por el usuario

El atributo internal es similar al control de acceso predeterminado en Java, aunque en Java no hay ningún nombre explícito para este nivel de acceso y sólo se puede alcanzar mediante la omisión de cualquier otro modificador de acceso. El atributo internal está disponible en ActionScript 3.0 para ofrecer la opción de indicar explícitamente la intención de hacer que una propiedad sólo sea visible para orígenes de llamada de su propio paquete.

Atributo static

El atributo static, que se puede utilizar con propiedades declaradas con las palabras clave var, const o function, permite asociar una propiedad a la clase en lugar de asociarla a instancias de la clase. El código externo a la clase debe llamar a propiedades estáticas utilizando el nombre de la clase en lugar de un nombre de instancia.

Las subclases no heredan las propiedades estáticas, pero las propiedades forman parte de una cadena de ámbitos de subclase. Esto significa que en el cuerpo de una subclase se puede utilizar una variable o un método estático sin hacer referencia a la clase en la que se definió.

Atributos de espacio de nombres definido por el usuario

Como alternativa a los atributos de control de acceso predefinidos se puede crear un espacio de nombres personalizado para usarlo como un atributo. Sólo se puede utilizar un atributo de espacio de nombres por cada definición y no se puede utilizar en combinación con uno de los atributos de control de acceso (public, private, protected, internal).

Variables

Las variables pueden declararse con las palabras clave var o const. Es posible cambiar los valores de las variables declaradas con la palabra clave var varias veces durante la ejecución de un script. Las variables declaradas con la palabra clave const se denominan constantes y se les puede asignar valores una sola vez. Un intento de asignar un valor nuevo a una constante inicializada provoca un error.

Variables estáticas

Las variables estáticas se declaran mediante una combinación de la palabra clave static y la sentencia var o const. Las variables estáticas, que se asocian a una clase en lugar de a una instancia de una clase, son útiles para almacenar y compartir información que se aplica a toda una clase de objetos. Por ejemplo, una variable estática es adecuada si se desea almacenar un recuento del número de veces que se crea una instancia de una clase o si se desea almacenar el número máximo de instancias de la clase permitidas.

En el ejemplo siguiente se crea una variable totalCount para hacer un seguimiento del número de instancias de clase creadas y una constante MAX_NUM para almacenar el número máximo de instancias creadas. Las variables totalCount y MAX_NUM son estáticas porque contienen valores que se aplican a la clase como un todo en lugar de a una instancia concreta.

class StaticVars 
{ 
    public static var totalCount:int = 0; 
    public static const MAX_NUM:uint = 16; 
}

El código externo a la clase StaticVars y a cualquiera de sus subclases sólo puede hacer referencia a las propiedades totalCount y MAX_NUM a través de la misma clase. Por ejemplo, el siguiente código funciona:

trace(StaticVars.totalCount); // output: 0 
trace(StaticVars.MAX_NUM); // output: 16

No se puede acceder a variables estáticas a través de una instancia de la clase, por lo que el código siguiente devuelve errores:

var myStaticVars:StaticVars = new StaticVars(); 
trace(myStaticVars.totalCount); // error 
trace(myStaticVars.MAX_NUM); // error

Las variables declaradas con las palabras clave static y const deben ser inicializadas a la vez que se declara la constante, como hace la clase StaticVars para MAX_NUM. No se puede asignar un valor a MAX_NUM dentro del constructor o de un método de instancia. El código siguiente generará un error, ya que no es una forma válida de inicializar una constante estática:

// !! Error to initialize static constant this way 
class StaticVars2 
{ 
    public static const UNIQUESORT:uint; 
    function initializeStatic():void 
    { 
        UNIQUESORT = 16; 
    } 
}

Variables de instancia

Las variables de instancia incluyen propiedades declaradas con las palabras clave var y const, pero sin la palabra clave static. Las variables de este tipo, que se asocian a instancias de clase en lugar de a una clase completa, son útiles para almacenar valores específicos de una instancia. Por ejemplo, la clase Array tiene una propiedad de instancia denominada length que almacena el número de elementos de conjunto contenidos en una instancia concreta de la clase Array.

En una subclase no se pueden sustituir las variables de instancia, aunque se declaren como var o const. Sin embargo, se puede obtener una funcionalidad similar a la sustitución de variables sustituyendo métodos de captador y definidor.

Métodos

Los métodos son funciones que forman parte de una definición de clase. Cuando se crea una instancia de la clase, se vincula un método a esa instancia. A diferencia de una función declarada fuera de una clase, un método sólo puede utilizarse desde la instancia a la que está asociado.

Los métodos se definen con la palabra clave function. Al igual que sucede con cualquier propiedad de clase, puede aplicar cualquiera de sus atributos a los métodos, incluyendo private, protected, public, internal, static o un espacio de nombres personalizado. Puede utilizar una sentencia de función como la siguiente:

public function sampleFunction():String {}

También se puede utilizar una variable a la que se asigna una expresión de función, de la manera siguiente:

public var sampleFunction:Function = function () {}

En la mayoría de los casos se deseará utilizar una sentencia de función en lugar de una expresión de función por los siguientes motivos:

  • Las sentencias de función son más concisas y fáciles de leer.

  • Permiten utilizar las palabras clave override y final.

  • Crean un vínculo más fuerte entre el identificador (es decir, el nombre de la función) y el código del cuerpo del método. Como es posible cambiar el valor de una variable con una sentencia de asignación, la conexión entre una variable y su expresión de función se puede hacer más fuerte en cualquier momento. Aunque se puede solucionar este problema declarando la variable con const en lugar de var, esta técnica no se considera una práctica recomendable, ya que hace que el código sea difícil de leer e impide el uso de las palabras clave override y final.

Un caso en el que hay que utilizar una expresión de función es cuando se elige asociar una función al objeto prototipo.

Métodos constructores

Los métodos constructores, denominados en ocasiones constructores, son funciones que comparten el nombre con la clase en la que se definen. Todo el código que se incluya en un método constructor se ejecutará siempre que una instancia de la clase se cree con la palabra clave new. Por ejemplo, el código siguiente define una clase simple denominada Example que contiene una sola propiedad denominada status. El valor inicial de la variable status se establece en la función constructora.

class Example 
{ 
    public var status:String; 
    public function Example() 
    { 
        status = "initialized"; 
    } 
} 
 
var myExample:Example = new Example(); 
trace(myExample.status); // output: initialized

Los métodos constructores sólo pueden ser públicos, pero el uso del atributo public es opcional. No se puede utilizar en un constructor ninguno de los otros especificadores de control de acceso, incluidos private, protected e internal . Tampoco se puede utilizar un espacio de nombres definido por el usuario con un método constructor.

Un constructor puede hacer una llamada explícita al constructor de su superclase directa utilizando la sentenciasuper(). Si no se llama explícitamente al constructor de la superclase, el compilador inserta automáticamente una llamada antes de la primera sentencia en el cuerpo del constructor. También se puede llamar a métodos de la superclase mediante el prefijo super como una referencia a la superclase. Si se decide utilizar super() y super en el mismo cuerpo de constructor, hay que asegurarse de llamar primero a super(). De lo contrario, la referencia super no se comportará de la manera esperada. También se debe llamar al constructor super() antes que a cualquier sentencia throw o return.

En el ejemplo siguiente se ilustra lo que sucede si se intenta utilizar la referencia super antes de llamar al constructor super(). Una nueva clase, ExampleEx, amplía la clase Example. El constructor de ExampleEx intenta acceder a la variable de estado definida en su superclase, pero lo hace antes de llamar a super(). La sentencia trace() del constructor de ExampleEx produce el valor null porque la variable status no está disponible hasta que se ejecuta el constructor super().

class ExampleEx extends Example 
{ 
    public function ExampleEx() 
    { 
        trace(super.status); 
        super(); 
    } 
} 
 
var mySample:ExampleEx = new ExampleEx(); // output: null

Aunque se puede utilizar la sentencia return dentro de un constructor, no se permite devolver un valor. Es decir, las sentencias return no deben tener expresiones o valores asociados. Por consiguiente, no se permite que los métodos constructores devuelvan valores, lo que significa que no se puede especificar ningún tipo de devolución.

Si no se define un método constructor en la clase, el compilador creará automáticamente un constructor vacío. Si la clase amplía otra clase, el compilador incluirá una llamada super() en el constructor que genera.

Métodos estáticos

Los métodos estáticos, también denominados métodos de clase, son métodos que se declaran con la palabra clave static. Estos métodos, que se asocian a una clase en lugar de a una instancia de clase, son útiles para encapsular la funcionalidad que afecta a algo más que el estado de una instancia individual. Como los métodos estáticos se asocian a una clase como un todo, sólo se puede acceder a dichos métodos a través de una clase, no a través de una instancia de la clase.

Los métodos estáticos son útiles para encapsular la funcionalidad que no se limita a afectar al estado de las instancias de clase. Es decir, un método debe ser estático si proporciona funcionalidad que no afecta directamente al valor de una instancia de clase. Por ejemplo, la clase Date tiene un método estático denominado parse(), que convierte una cadena en un número. El método es estático porque no afecta a una instancia individual de la clase. El método parse() recibe una cadena que representa un valor de fecha, analiza la cadena y devuelve un número con un formato compatible con la representación interna de un objeto Date. Este método no es un método de instancia porque no tiene sentido aplicar el método a una instancia de la clase Date.

El método parse() estático puede compararse con uno de los métodos de instancia de la clase Date, como getMonth(). El método getMonth() es un método de instancia porque opera directamente en el valor de una instancia recuperando un componente específico, el mes, de una instancia de Date.

Como los métodos estáticos no están vinculados a instancias individuales, no se pueden utilizar las palabras clave this o super en el cuerpo de un método estático. Las referencias this y super sólo tienen sentido en el contexto de un método de instancia.

En contraste con otros lenguajes de programación basados en clases, en ActionScript 3.0 los métodos estáticos no se heredan.

Métodos de instancia

Los métodos de instancia son métodos que se declaran sin la palabra clave static. Estos métodos, que se asocian a instancias de una clase en lugar de a la clase como un todo, son útiles para implementar funcionalidad que afecta a instancias individuales de una clase. Por ejemplo, la clase Array contiene un método de instancia denominado sort(), que opera directamente en instancias de Array.

En el cuerpo de un método de instancia, las variables estáticas y de instancia están dentro del ámbito, lo que significa que se puede hacer referencia a las variables definidas en la misma clase mediante un identificador simple. Por ejemplo, la clase siguiente, CustomArray, amplía la clase Array. La clase CustomArray define una variable estática denominada arrayCountTotal para hacer un seguimiento del número total de instancias de clase, una variable de instancia denominada arrayNumber que hace un seguimiento del orden en que se crearon las instancias y un método de instancia denominado getPosition() que devuelve los valores de estas variables.

public class CustomArray extends Array 
{ 
    public static var arrayCountTotal:int = 0; 
    public var arrayNumber:int; 
 
    public function CustomArray() 
    { 
        arrayNumber = ++arrayCountTotal; 
    } 
     
    public function getArrayPosition():String 
    { 
         return ("Array " + arrayNumber + " of " + arrayCountTotal); 
    } 
}

Aunque el código externo a la clase debe acceder a la variable estática arrayCountTotal a través del objeto de clase mediante CustomArray.arrayCountTotal, el código que reside dentro del cuerpo del método getPosition() puede hacer referencia directamente a la variable estática arrayCountTotal. Esto se cumple incluso para variables estáticas de superclases. Aunque en ActionScript 3.0 las propiedades estáticas no se heredan, las propiedades estáticas de las superclases están dentro del ámbito. Por ejemplo, la clase Array tiene unas pocas variables estáticas, una de las cuales es una constante denominada DESCENDING. El código que reside en una subclase de Array puede acceder a la constante estática DESCENDING mediante un identificador simple:

public class CustomArray extends Array 
{ 
    public function testStatic():void 
    { 
        trace(DESCENDING); // output: 2 
    } 
}

El valor de la referencia this en el cuerpo de un método de instancia es una referencia a la instancia a la que está asociado el método. El código siguiente muestra que la referencia this señala a la instancia que contiene el método:

class ThisTest 
{ 
    function thisValue():ThisTest 
    { 
        return this; 
    } 
} 
 
var myTest:ThisTest = new ThisTest(); 
trace(myTest.thisValue() == myTest); // output: true

La herencia de los métodos de instancia se puede controlar con las palabras clave override y final. Se puede utilizar el atributo override para redefinir un método heredado y el atributo final para evitar que las subclases sustituyan un método.

Métodos descriptores de acceso (captador y definidor)

Las funciones descriptoras de acceso get y set, también denominadas captadores y definidores, permiten implementar los principios de programación relacionados con la ocultación de información y encapsulación a la vez que ofrecen una interfaz de programación fácil de usar para las clases que se crean. Estas funciones permiten mantener las propiedades de clase como privadas de la clase ofreciendo a los usuarios de la clase acceso a esas propiedades como si accedieran a una variable de clase en lugar de llamar a un método de clase.

La ventaja de este enfoque es que permite evitar las funciones descriptoras de acceso tradicionales con nombres poco flexibles, como getPropertyName() y setPropertyName(). Otra ventaja de los captadores y definidores es que permiten evitar tener dos funciones públicas por cada propiedad que permita un acceso de lectura y escritura.

La siguiente clase de ejemplo, denominada GetSet, incluye funciones descriptoras de acceso get y set denominadas publicAccess() que proporcionan acceso a la variable privada denominada privateProperty:

class GetSet 
{ 
    private var privateProperty:String; 
     
    public function get publicAccess():String 
    { 
        return privateProperty; 
    } 
     
    public function set publicAccess(setValue:String):void 
    { 
        privateProperty = setValue; 
    } 
}

Si se intenta directamente acceder a la propiedad privateProperty se producirá un error, como se muestra a continuación:

var myGetSet:GetSet = new GetSet(); 
trace(myGetSet.privateProperty); // error occurs

En su lugar, un usuario de la clase GetSet utilizará algo que parece ser una propiedad denominada publicAccess, pero que en realidad es un par de funciones descriptoras de acceso get y set que operan en la propiedad privada denominada privateProperty. En el ejemplo siguiente se crea una instancia de la clase GetSet y después se establece el valor de privateProperty mediante el descriptor de acceso público denominado publicAccess:

var myGetSet:GetSet = new GetSet(); 
trace(myGetSet.publicAccess); // output: null 
myGetSet.publicAccess = "hello"; 
trace(myGetSet.publicAccess); // output: hello

Las funciones captadoras y definidoras también permiten sustituir propiedades heredadas de una superclase, algo que no es posible al usar variables miembro de clase normales. Las variables miembro de clase que se declaran mediante la palabra clave var no se pueden sustituir en una subclase. Sin embargo, las propiedades que se crean mediante funciones captadoras y definidoras no tienen esta restricción. Se puede utilizar el atributo override en funciones captadoras y definidoras heredadas de una superclase.

Métodos vinculados

Un método vinculado, a veces denominado cierre de método, es simplemente un método que se extrae de su instancia. Los métodos que se pasan como argumentos a una función o se devuelven como valores desde una función son ejemplos de métodos vinculados. Una de las novedades de ActionScript 3.0 es que un método vinculado es similar a un cierre de función, ya que conserva su entorno léxico incluso cuando se extrae de su instancia. Sin embargo, la diferencia clave entre un método vinculado y un cierre de función es que la referencia this para un método vinculado permanece vinculada a la instancia que implementa el método. Es decir, la referencia this de un método vinculado siempre señala al objeto original que implementó el método. Para los cierres de función, la referencia this es genérica, lo que significa que señala al objeto con el que esté relacionada la función cuando se llame.

Es importante comprender los métodos vinculados para utilizar la palabra clave this. Debe recordarse que la palabra clave this proporciona una referencia al objeto principal de un método. La mayoría de los programadores que utilizan ActionScript esperan que la palabra clave this siempre represente el objeto o la clase que contiene la definición de un método. Sin embargo, sin la vinculación de métodos esto no se cumplirá siempre. Por ejemplo, en las versiones anteriores de ActionScript, la referencia this no siempre hacía referencia a la instancia que implementaba el método. En ActionScript 2.0, cuando se extraen métodos de una instancia no sólo no se vincula la referencia this a la instancia original, sino que además las variables y los métodos miembro de la clase de la instancia no están disponibles. Esto es no un problema en ActionScript 3.0 porque se crean métodos vinculados automáticamente cuando se pasa un método como parámetro. Los métodos vinculados garantizan que la palabra clave this siempre haga referencia al objeto o la clase en que se define un método.

El código siguiente define una clase denominada ThisTest, que contiene un método denominado foo() que define el método vinculado y un método denominado bar() que devuelve el método vinculado. El código externo a la clase crea una instancia de la clase ThisTest, llama al método bar() y almacena el valor devuelto en una variable denominada myFunc.

class ThisTest 
{ 
    private var num:Number = 3; 
    function foo():void // bound method defined 
    { 
        trace("foo's this: " + this); 
        trace("num: " + num); 
    } 
    function bar():Function 
    { 
        return foo; // bound method returned 
    } 
} 
 
var myTest:ThisTest = new ThisTest(); 
var myFunc:Function = myTest.bar(); 
trace(this); // output: [object global] 
myFunc(); 
/* output:  
foo's this: [object ThisTest] 
output: num: 3 */

Las dos últimas líneas de código muestran que la referencia this del método vinculado foo() sigue señalando a una instancia de la clase ThisTest, aunque la referencia this de la línea inmediatamente anterior señala al objeto global. Además, el método vinculado almacenado en la variable myFunc sigue teniendo acceso a las variables miembro de la clase ThisTest. Si se ejecutara este mismo código en ActionScript 2.0, las referencias this coincidirían y el valor de la variable num sería undefined.

La adición de métodos vinculados se aprecia mejor en aspectos como los controladores de eventos, ya que el método addEventListener() requiere que se pase una función o un método como un argumento.

Enumeraciones con clases

Las enumeraciones son tipos de datos personalizados que se crean para encapsular un pequeño conjunto de valores. ActionScript 3.0 no ofrece una capacidad de enumeración específica, a diferencia de C++, que incluye la palabra clave enum, o Java, con su interfaz Enumeration. No obstante, se pueden crear enumeraciones utilizando clases y constantes estáticas. Por ejemplo, la clase PrintJob en ActionScript 3.0 utiliza una enumeración denominada PrintJobOrientation para almacenar el conjunto de valores formado por "landscape" y "portrait", como se muestra en el código siguiente:

public final class PrintJobOrientation 
{ 
    public static const LANDSCAPE:String = "landscape"; 
    public static const PORTRAIT:String = "portrait"; 
}

Por convención, una clase de enumeración se declara con el atributo final porque no es necesario ampliarla. La clase sólo contiene miembros estáticos, lo que significa que no se crean instancias de la clase. sino que se accede a los valores de la enumeración directamente a través del objeto de clase, como se indica en el siguiente fragmento de código:

var pj:PrintJob = new PrintJob(); 
if(pj.start()) 
{ 
    if (pj.orientation == PrintJobOrientation.PORTRAIT) 
    { 
        ... 
    } 
    ... 
}

Todas las clases de enumeración en ActionScript 3.0 sólo contienen variables de tipo String, int o uint. La ventaja de utilizar enumeraciones en lugar de valores literales numéricos o de cadena es que es más fácil detectar errores tipográficos con las enumeraciones. Si se escribe incorrectamente el nombre de una enumeración, el compilador de ActionScript genera un error. Si se utilizan valores literales, el compilador no mostrará ninguna advertencia en caso de que encuentre una palabra escrita incorrectamente o se utilice un número incorrecto. En el ejemplo anterior, el compilador genera un error si el nombre de la constante de enumeración es incorrecto, como se indica en el siguiente fragmento:

    if (pj.orientation == PrintJobOrientation.PORTRAI) // compiler error

Sin embargo, el compilador no generará un error si se escribe incorrectamente un valor literal de cadena, como se muestra a continuación:

    if (pj.orientation == "portrai") // no compiler error

Otra técnica para crear enumeraciones también implica crear una clase independiente con propiedades estáticas para la enumeración. No obstante, esta técnica difiere en que cada una de las propiedades estáticas contiene una instancia de la clase en lugar de una cadena o un valor entero. Por ejemplo, el código siguiente crea una clase de enumeración para los días de la semana:

public final class Day 
{ 
    public static const MONDAY:Day = new Day(); 
    public static const TUESDAY:Day = new Day(); 
    public static const WEDNESDAY:Day = new Day(); 
    public static const THURSDAY:Day = new Day(); 
    public static const FRIDAY:Day = new Day(); 
    public static const SATURDAY:Day = new Day(); 
    public static const SUNDAY:Day = new Day(); 
}

En ActionScript 3.0 no se emplea esta técnica, pero la utilizan muchos desarrolladores que prefieren la verificación de tipos mejorada que proporciona. Por ejemplo, un método que devuelve un valor de enumeración puede restringir el valor devuelto al tipo de datos de la enumeración. El código siguiente muestra, además de una función que devuelve un día de la semana, una llamada a función que utiliza el tipo de la enumeración como una anotación de tipo:

function getDay():Day 
{ 
    var date:Date = new Date(); 
    var retDay:Day; 
    switch (date.day) 
    { 
        case 0: 
            retDay = Day.MONDAY; 
            break; 
        case 1: 
            retDay = Day.TUESDAY; 
            break; 
        case 2: 
            retDay = Day.WEDNESDAY; 
            break; 
        case 3: 
            retDay = Day.THURSDAY; 
            break; 
        case 4: 
            retDay = Day.FRIDAY; 
            break; 
        case 5: 
            retDay = Day.SATURDAY; 
            break; 
        case 6: 
            retDay = Day.SUNDAY; 
            break; 
    } 
    return retDay; 
} 
 
var dayOfWeek:Day = getDay();

También se puede mejorar la clase Day de forma que asocie un entero con cada día de la semana y proporcione un método toString() que devuelva una representación de cadena del día.

Clases de activos incorporados

ActionScript 3.0 utiliza clases especiales, denominadas clases de activos incorporados, para representar elementos incorporados. Un activo incorporado es un activo, como un sonido, una imagen o una fuente, que se incluye en un archivo SWF en tiempo de compilación. Incorporar un activo en lugar de cargarlo dinámicamente garantiza que estará disponible en tiempo de ejecución, pero a cambio el tamaño del archivo SWF será mayor.

Uso de clases de activos incorporados en Flash Professional

Para incorporar un activo, hay que añadir primero el activo a una biblioteca de archivo FLA. A continuación, hay que usar la propiedad linkage del activo para asignar un nombre a la clase de activo incorporado del activo. Si no se encuentra una clase con ese nombre en la ruta de clases, se generará una clase automáticamente. Después se puede utilizar una instancia de la clase de activo incorporado y utilizar las propiedades y los métodos definidos por la clase. Por ejemplo, se puede utilizar el código siguiente para reproducir un sonido incorporado vinculado a una clase de activo incorporado denominada PianoMusic:

var piano:PianoMusic = new PianoMusic(); 
var sndChannel:SoundChannel = piano.play();

De forma alternativa, se puede utilizar la etiqueta de metadatos [Embed] para incorporar activos en un proyecto de Flash Professional, tal y como se describe a continuación. Si se utiliza la etiqueta [Embed] en el código, Flash Professional emplea el compilador Flex para compilar el proyecto en lugar del compilador Flash Professional.

Uso de clases de activos incorporados mediante el compilador Flex

Si se está compilando código con el compilador Flex, para incorporar un activo al código de ActionScript, utilice la etiqueta de metadatos [Embed]. Coloque el activo en la carpeta principal de código fuente o en otra carpeta situada en la ruta de compilación del proyecto. Cuando el compilador Flex encuentra una etiqueta de metadatos Embed, crea automáticamente la clase de activo incorporado. Puede acceder a la clase a través una variable de tipo de datos Class que se declara de forma inmediata siguiendo la etiqueta de metadatos [Embed]. Por ejemplo, el siguiente código incorpora un sonido denominado sound1.mp3 y utiliza una variable llamada soundCls para almacenar una referencia a la clase de activo incorporado asociada al sonido. Posteriormente el ejemplo crea una instancia de la clase de activo incorporado y llama al método play() en dicha instancia:

package 
{ 
    import flash.display.Sprite; 
    import flash.media.SoundChannel; 
    import mx.core.SoundAsset; 
 
    public class SoundAssetExample extends Sprite 
    { 
        [Embed(source="sound1.mp3")] 
        public var soundCls:Class; 
         
        public function SoundAssetExample() 
        { 
            var mySound:SoundAsset = new soundCls() as SoundAsset; 
            var sndChannel:SoundChannel = mySound.play(); 
        } 
    } 
}

Adobe Flash Builder

Para utilizar la etiqueta de metadatos [Embed] en un proyecto de ActionScript de Flash Builder, debe importar todas las clases necesarias de la arquitectura Flex. Por ejemplo, para incorporar sonidos, debe importar la clase mx.core.SoundAsset. Para utilizar la arquitectura Flex, incluya el archivo framework.swc en la ruta de compilación de ActionScript. Con ello aumentará el tamaño del archivo SWF.

Adobe Flex

Otra posibilidad consiste en incorporar en Flex un activo con la directiva @Embed() en una definición de etiqueta MXML.