Associativa arrayer

Flash Player 9 och senare, Adobe AIR 1.0 och senare

I en associativ array, som ibland även kallas hash eller map, används nycklar i stället för numeriska index för att ordna lagrade värden. Varje nyckel i en associativ array är en unik sträng som används för att få åtkomst till lagrade värden. En associativ array är en instans av klassen Object, vilket innebär att varje nyckel motsvarar ett egenskapsnamn. Associativa arrayer är osorterade samlingar av par med nycklar och värden. I koden förutsätts inte att nycklarna för en associativ array ligger i någon särskild ordning.

I ActionScript 3.0 ingår också en avancerad typ av associativ array, som kallas för ordlista. Ordlistor, som är instanser av klassen Dictionary i flash.utils-paketet, använder nycklar som kan vara av valfri datatyp. Med andra ord är Dictionary-nycklarna inte begränsade till värden av typen String.

Associativa arrayer med strängnycklar

Det finns två sätt att skapa associativa arrayer i ActionScript 3.0: Det första är att använda en Object-instans. Genom att använda en Object-instans kan du initiera arrayen med en objektlitteral. En instans av Object-klassen, som även kallas ett generiskt objekt, är funktionsmässigt identisk med en associativ array. Varje egenskapsnamn för det generiska objektet fungerar som en nyckel som ger åtkomst till ett sparat värde.

I exemplet nedan skapas en associativ array med namnet monitorInfo och här används en objektlitteral för att initiera arrayen med två nyckel-/värde-par:

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

Om du inte behöver initiera arrayen när den deklareras kan du använda konstruktorn Object för att skapa arrayen, vilket visas i nästa exempel:

var monitorInfo:Object = new Object();

När arrayen har skapats, antingen med hjälp av en objektlitteral eller konstruktorn för klassen Object, kan du lägga till nya värden i arrayen med hjälp av operatorn för arrayåtkomst ([]) eller punktoperatorn (.). I följande exempel läggs två nya värden till i 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

Observera att nyckeln med namnet aspect ratio innehåller ett blanksteg. Detta fungerar med operatorn för arrayåtkomst ([]), men leder till ett fel med punktoperatorn. Därför bör du inte använda blanksteg i nyckelnamn.

Det andra sättet att skapa en associativ array är att använda konstruktorn Array (eller konstruktorn för någon dynamisk klass) och sedan antingen operatorn för arrayåtkomst ([]) eller punktoperatorn (.) för att lägga till par med nyckel och värde till arrayen. Om du deklarerar att den associativa arrayen är av typen Array, kan du inte använda en objektlitteral för att initialisera den. I följande exempel skapas en associativ array med namnet monitorInfo med hjälp av konstruktorn Array, och nycklar med namnen type och resolution läggs till tillsammans med respektive värden:

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

Det finns ingen fördel med att använda kontruktorn Array för att skapa en associativ array. Du kan inte använda egenskapen Array.length eller någon annan metod för klassen Array med associativa arrayer, även om du använder konstruktorn Array eller datatypen Array. Konstruktorn Array fungerar bäst när du använder den för att skapa indexerade arrayer.

Associativa arrayer med objektnycklar (ordlistor)

Med klassen Dictionary kan du skapa en associativ array där objekt används som nycklar och inte strängar. Sådana arrayer kallas ibland ordlistor, hash-tabeller eller ”maps”. Tänk dig ett program som används för att bestämma platsen för ett Sprite-objekt utifrån dess association till en speciell behållare. Du kan då använda ett Dictionary-objekt för att mappa varje Sprite-object till en behållare.

I exemplet nedan skapas tre instanser av klassen Sprite för att utgöra nycklar för objektet Dictionary. Varje nyckel tilldelas ett värde på antingen GroupA eller GroupB. Värdena kan ha alla datatyper, men i detta exempel är både GroupA och GroupB instanser av klassen Object. Därav följer att du får åtkomst till värdet som associeras med respektive nyckel via operatorn för arrayåtkomst ([]), vilket framgår av följande kod:

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");  
}

Iterera med objektnycklar

Du kan iterera igenom innehållet i ett Dictionary-objekt med antingen en for..in-slinga eller en for each..in-slinga. Med en for..in-slinga itererar du med hjälp av nycklar, medan du för en for each..in-slinga använder värdet som associerats med varje nyckel.

Du använder for..in-slingan för att få direkt åtkomst till objektnycklarna i ett Dictionary-objekt. Du kan även få åtkomst till värden i objektet Dictionary med operatorn för arrayåtkomst ([]). I följande kod används det tidigare exemplet med groupMap-ordlistan för att visa hur du itererar igenom ett Dictionary-objekt med for..in-slinga:

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

Du använder for each..in-slingan för att få direkt åtkomst till värden i ett Dictionary-objekt. I följande kod används exemplet med groupMap-ordlistan för att visa hur du itererar igenom ett Dictionary-objekt med for each..in-slinga:

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

Objektnycklar och minneshantering

I Adobe® Flash® Player och Adobe® AIR™ används ett system för att samla ihop skräp för att rensa minnet från sådant som inte längre behövs. När det inte längre finns några referenser som pekar mot ett objekt uppfyller objektet villkoren för att betraktas som skräp och det kommer då att rensas bort nästa gång som skräpsamlingen utförs. I nästa exempel skapas ett nytt objekt och variabeln myObject tilldelas en referens till objektet:

var myObject:Object = new Object();

Så länge det finns några referenser till objektet går det inte att använda skräpsamlingssystemet för att återställa den minneskapacitet som objektet upptar. Om värdet för myObject ändras så att det pekar på ett annat objekt eller anges som null blir det minnesutrymme, som upptogs av det ursprungliga objektet, tillgängligt för skräpsamling. Detta förutsätter dock att det inte finns några andra referenser till det ursprungliga objektet.

Om du använder myObject som en nyckel i ett Dictionary-objekt skapar du en ny referens till det ursprungliga objektet. I följande exempel skapas två referenser till ett objekt – variabeln myObject och nyckeln i objektet myMap:

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

Om du vill att det objekt som myObject refererar till ska vara tillgängligt för skräpsamling måste du ta bort alla referenser till det. I detta fall måste du ändra värdet för myObject och radera nyckeln myObject från myMap, vilket framgår av följande exempel:

myObject = null; 
delete myMap[myObject];

Du kan också använda parametern useWeakReference i Dictionary-konstruktorn för att göra alla Dictionary-nycklar till svaga referenser. Skräpsamlingssystemet ignorerar svaga referenser, vilket innebär att ett objekt som endast innehåller svaga referenser kan tas bort vid en skräpsamling. I nästa exempel behöver du inte ta bort nyckeln myObject från myMap för att göra objektet tillgängligt för skräpsamling:

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.