Conjuntos asociativos

Flash Player 9 y posterior, Adobe AIR 1.0 y posterior

Un conjunto asociativo, también denominado a veces hash o asignación , utiliza claves en lugar de un índice numérico para organizar los valores almacenados. Cada clave de un conjunto asociativo es una cadena única que se utiliza para acceder a un valor almacenado. Un conjunto asociativo es una instancia de la clase Object, lo que significa que cada clave corresponde a un nombre de propiedad. Los conjuntos asociativos son colecciones no ordenadas de pares formados por una clave y un valor. Hay que tener en cuenta en el código que las claves de un conjunto asociativo no tienen un orden específico.

ActionScript 3.0 también introduce un tipo avanzado de conjunto asociativo denominado dictionary . Los diccionarios, que son instancias de la clase Dictionary del paquete flash.utils, utilizan claves que pueden ser de cualquier tipo de datos. Es decir, las claves de diccionario no están limitadas a valores de tipo String.

Conjuntos asociativos con claves de tipo cadena

Existen dos formas de crear conjuntos asociativos en ActionScript 3.0. La primera es utilizar una instancia de Object. Al utilizar una instancia de Object, es posible inicializar el conjunto con un literal de objeto. Una instancia de la clase Object, conocida también como objeto genérico , es funcionalmente idéntica a un conjunto asociativo. El nombre de cada propiedad del objeto genérico actúa a modo de clave que permite acceder a un valor almacenado.

Este código crea un conjunto asociativo denominado monitorInfo y utiliza un literal de objeto para inicializar el conjunto con dos pares clave/valor.

var monitorInfo:Object = {type:"Flat Panel", resolution:"1600 x 1200"}; 
trace(monitorInfo["type"], monitorInfo["resolution"]);  
// output: Flat Panel 1600 x 1200

Si no es necesario inicializar el conjunto en el momento de declararlo, se puede utilizar el constructor Object para crear el conjunto de la manera siguiente:

var monitorInfo:Object = new Object();

Una vez creado un conjunto con un literal de objeto o el constructor de la clase Object, se pueden añadir valores nuevos al conjunto mediante el operador de acceso a conjunto ( [] ) o el operador punto ( . ). En el ejemplo siguiente se añaden dos valores nuevos a monitorArray :

monitorInfo["aspect ratio"] = "16:10"; // bad form, do not use spaces 
monitorInfo.colors = "16.7 million"; 
trace(monitorInfo["aspect ratio"], monitorInfo.colors); 
// output: 16:10 16.7 million

Hay que tener en cuenta que la clave denominada aspect ratio contiene un espacio en blanco. Esto es posible con el operador de acceso a conjunto ( [] ) pero genera un error si se intenta con el operador punto. No es recomendable utilizar espacios en los nombres de claves.

La segunda forma de crear un conjunto asociativo consiste en utilizar el constructor Array (o el constructor de cualquier clase dinámica) y posteriormente utilizar el operador de acceso a conjunto ( [] ) o el operador punto ( . ) para agregar pares de clave y valor al conjunto. Si se declara el conjunto asociativo con el tipo Array, no se podrá utilizar un literal de objeto para inicializar el conjunto. En el ejemplo siguiente se crea un conjunto asociativo denominado monitorInfo empleando el constructor de Array y se añaden claves denominadas type y resolution , junto con sus valores:

var monitorInfo:Array = new Array(); 
monitorInfo["type"] = "Flat Panel"; 
monitorInfo["resolution"] = "1600 x 1200"; 
trace(monitorInfo["type"], monitorInfo["resolution"]);  
// output: Flat Panel 1600 x 1200

La utilización del constructor de Array para crear un conjunto asociativo no aporta ninguna ventaja. No se puede utilizar la propiedad Array.length ni ninguno de los métodos de la clase Array con los conjuntos asociativos, incluso si se utiliza el constructor de Array o el tipo de datos Array. Es mejor dejar el uso del constructor de Array para la creación de conjuntos indexados.

Conjuntos asociativos con claves de tipo objeto (Diccionarios)

Se puede utilizar la clase Dictionary para crear un conjunto asociativo que utilice objetos como claves en lugar de cadenas. Estos conjuntos se llaman a veces diccionarios, hashes o asignaciones. Por ejemplo, considérese una aplicación que determina la ubicación de un objeto Sprite a partir de su asociación con un contenedor específico. Se puede utilizar un objeto Dictionary para asignar cada objeto Sprite a un contenedor.

El código siguiente crea tres instancias de la clase Sprite que serán las claves del objeto Dictionary. A cada clave se le asigna un valor GroupA o GroupB . Los valores pueden ser de cualquier tipo de datos, pero en este ejemplo GroupA y GroupB son instancias de la clase Object. Posteriormente se podrá acceder al valor asociado con cada clave mediante el operador de acceso a conjunto ( [] ), como se indica en el código siguiente:

import flash.display.Sprite; 
import flash.utils.Dictionary; 
 
var groupMap:Dictionary = new Dictionary(); 
 
// objects to use as keys 
var spr1:Sprite = new Sprite(); 
var spr2:Sprite = new Sprite(); 
var spr3:Sprite = new Sprite(); 
 
// objects to use as values 
var groupA:Object = new Object(); 
var groupB:Object = new Object(); 
 
// Create new key-value pairs in dictionary. 
groupMap[spr1] = groupA; 
groupMap[spr2] = groupB; 
groupMap[spr3] = groupB; 
 
if (groupMap[spr1] == groupA) 
{ 
    trace("spr1 is in groupA");  
} 
if (groupMap[spr2] == groupB) 
{ 
    trace("spr2 is in groupB");  
} 
if (groupMap[spr3] == groupB) 
{ 
    trace("spr3 is in groupB");  
}

Iteración con claves de tipo objeto

Puede repetir el contenido de un objeto Dictionary con un bucle for..in o un bucle for each..in . El bucle for..in permite la repetición en función de las claves, mientras que el bucle for each..in lo hace en función de los valores asociados con cada clave.

Utilice el bucle for..in para dirigir el acceso a las claves de tipo Object de un objeto Dictionary. También se puede acceder a los valores del objeto Dictionary con el operador de acceso a conjunto ( [] ). El código siguiente utiliza el ejemplo anterior del diccionario groupMap para mostrar la forma de repetición de un objeto Dictionary con el bucle for..in:

for (var key:Object in groupMap) 
{ 
    trace(key, groupMap[key]); 
} 
/* output: 
[object Sprite] [object Object] 
[object Sprite] [object Object] 
[object Sprite] [object Object] 
*/

El bucle for each..in para dirigir el acceso a los valores de un objeto Dictionary. El código siguiente también utiliza el diccionario groupMap para mostrar la forma de repetición de un objeto Dictionary con el bucle for each..in:

for each (var item:Object in groupMap) 
{ 
    trace(item); 
} 
/* output: 
[object Object] 
[object Object] 
[object Object] 
*/

Claves de tipo objeto y administración de memoria

Adobe® Flash® Player y Adobe® AIR™ utilizan un sistema de eliminación de datos innecesarios para recuperar la memoria que ya no se está utilizando. Cuando ya no quedan referencias a un objeto, el objeto se convierte en disponible para la eliminación de datos innecesarios y se recupera la memoria la próxima vez que se ejecute el sistema de eliminación de datos innecesarios. Por ejemplo, el código siguiente crea un nuevo objeto y asigna una referencia al objeto a la variable myObject :

var myObject:Object = new Object();

Con que exista una referencia al objeto, el sistema de eliminación de datos innecesarios no recuperará la memoria ocupada por el objeto. Si se cambia el valor de myObject de forma que haga referencia a un objeto distinto o se establece en el valor null , la memoria ocupada por el objeto original se convierte en disponible para la eliminación de datos innecesarios, pero solo si no hay otras referencias al objeto original.

Si se utiliza myObject como clave de un objeto Dictionary, se crea otra referencia al objeto original. Por ejemplo, el código siguiente crea dos referencias a un objeto: la variable myObject y la clave del objeto myMap :

import flash.utils.Dictionary; 
 
var myObject:Object = new Object(); 
var myMap:Dictionary = new Dictionary(); 
myMap[myObject] = "foo";

Para hacer que el objeto al que hace referencia myObject esté disponible para la eliminación de datos innecesarios, hay que eliminar todas las referencias a dicho objeto. En este caso, hay que cambiar el valor de myObject y eliminar la clave myObject de myMap , como se indica en el código siguiente:

myObject = null; 
delete myMap[myObject];

Como alternativa, se puede utilizar el parámetro useWeakReference del constructor de Dictionary para convertir todas las claves del diccionario en referencias débiles . El sistema de eliminación de datos innecesarios no tiene en cuenta las referencias débiles, lo que significa que un objeto que solo tenga referencias débiles estará disponible para la eliminación de datos innecesarios. Por ejemplo, en el código siguiente no es necesario eliminar la clave myObject de myMap para hacer que el objeto esté disponible para la eliminación de datos innecesarios:

import flash.utils.Dictionary; 
 
var myObject:Object = new Object(); 
var myMap:Dictionary = new Dictionary(true); 
myMap[myObject] = "foo"; 
myObject = null; // Make object eligible for garbage collection.