Ассоциативные массивы

Flash Player 9 и более поздних версий, Adobe AIR 1.0 и более поздних версий

Ассоциативный массив, иногда называемый хеш-таблицей или сопоставлением, использует для организации хранимых значений ключи вместо числовых индексов. Каждый ключ в ассоциативном массиве — это уникальная строка, используемая для доступа к хранимому значению. Ассоциативный массив — это экземпляр класса Object, то есть каждый ключ соответствует имени свойства. Ассоциативные массивы — это неупорядоченные наборы пар «ключ-значение». Ключи в ассоциативном массиве не подчиняются какому-либо порядку.

В ActionScript 3.0 также предусмотрен расширенный тип ассоциативного массива под названием словарь. Словари являются экземплярами класса Dictionary в пакете flash.utils и используют ключи, которые могут быть любым типом данных. Иными словами, ключи словаря не ограничиваются значениями типа String.

Ассоциативные массивы со строками-ключами

В ActionScript 3.0 ассоциативные массивы можно создавать двумя способами. Во-первых, можно использовать экземпляр Object. С помощью экземпляра Object можно инициализировать массив, используя литерал объекта. Экземпляр класса Object, также называемый родовым объектом, по своим функциям идентичен ассоциативному массиву. Имя каждого из свойств родового объекта служит ключом доступа к сохраненному значению.

В примере ниже показано, как создавать ассоциативный массив monitorInfo с помощью литерала объекта, чтобы инициализировать массив с двумя парами «ключ-значение».

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

Если вам не нужно инициализировать массив во время объявления, можно использовать для создания массива конструктор Object, как показано ниже:

var monitorInfo:Object = new Object();

После создания массива с помощью литерала объекта или конструктора класса Object можно добавить к массиву новые значения либо с помощью оператора доступа к массиву ([]), либо с помощью оператора «точка» (.). В примере ниже показано, как добавить два новых значения в массив 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

Обратите внимание, что ключ aspect ratio содержит символ пробела. При использовании с оператором доступа к массиву ([]) это допустимо, но при использовании с оператором «точка» приведет к ошибке. Использовать пробелы в именах ключей не рекомендуется.

Второй способ создать ассоциативный массив — использовать конструктор Array (или конструктор любого динамического класса), а затем использовать оператор доступа к массиву ([]) или «точка» (.) для добавления пар «ключ-значение» в массив. Если вы объявляете ассоциативный массив как массив любого типа класса Array, нельзя использовать для инициализации массива литерал объекта. В примере ниже показано, как создать ассоциативный массив monitorInfo с помощью конструктора Array и добавить ключ type и ключ resolution вместе со значениями:

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

Использование конструктора Array для создания ассоциативного массива не дает никаких особых преимуществ. С ассоциативными массивами нельзя использовать свойство Array.length или любой из методов класса Array, даже если вы используете конструктор Array или тип данных Array. Конструктор Array лучше всего подходит для создания индексных массивов.

Ассоциативные массивы с объектами-ключами (Словари)

Можно использовать класс Dictionary для создания ассоциативного массива, использующего в качестве ключей объекты, а не строки. Такие массивы иногда называют словарями, хеш-таблицами или преобразованиями. Например, рассмотрим приложение, определяющее расположение объекта Sprite на основании его связи с определенным контейнером. Можно использовать объект Dictionary, чтобы сопоставить каждый объект Sprite с контейнером.

В примере ниже создаются три экземпляра класса Sprite, которые служат ключами для объекта Dictionary. Каждому ключу задается значение GroupA или GroupB. Значения могут быть любого типа данных, но в этом примере и GroupA, и GroupB являются экземплярами класса Object. Следовательно, доступ к значениям, связанным с каждым из ключей с оператором доступа к массиву ([]), осуществляется способом, показанным ниже:

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

Итерации с объектами-ключами

Можно выполнять итерацию в объекте Dictionary с помощью цикла for..in или for each..in. Цикл for..in позволяет выполнять итерацию на основе ключей, а цикл for each..in — на основе значений, связанных с ключами.

Используйте цикл for..in для прямого доступа к объектам-ключам объекта Dictionary. Доступ к значениям объекта Dictionary возможен и без оператора доступа к массиву ([]). В приведенном ниже коде словарь groupMap из предыдущего примера используется для выполнения итерации в объекте Dictionary с помощью цикла 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] 
*/

Используйте цикл for each..in для прямого доступа к значениям объекта Dictionary. В приведенном ниже коде словарь groupMap используется для выполнения итерации в объекте Dictionary с помощью цикла for each..in:

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

Объекты-ключи и управление памятью

Проигрыватель Adobe® Flash® Player и среда Adobe® AIR™ используют систему сборки мусора для восстановления памяти, которая больше не используется. Когда на объект не ведет ни одна ссылка, он становится кандидатом на сборку в мусор, поэтому при следующей сборке мусора занимаемая им память высвобождается. Например, в приведенном ниже коде создается новый объект, а переменной myObject назначается ссылка на объект:

var myObject:Object = new Object();

Покуда на объект указывает хотя бы одна ссылка, сборщик мусора не будет высвобождать занимаемую им память. Если значение myObject меняется и теперь указывает на другой объект или становится null, то память, занимаемая исходным объектом, подлежит сборке в мусор, но лишь в том случае, если на исходный объект не ведут другие ссылки.

Если myObject используется как ключ в объекте Dictionary, создается еще одна ссылка на исходный объект. Например, в приведенном ниже коде создаются две ссылки на объект — переменную myObject и ключ в объекте myMap:

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

Чтобы объект, на который ссылается myObject, мог быть собран в мусор, необходимо удалить все ссылки на него. В этом случае нужно изменить значение myObject и удалить ключ myObject из myMap, как показано ниже:

myObject = null; 
delete myMap[myObject];

Вы также можете использовать параметр useWeakReference конструктора Dictionary, чтобы превратить все ключи словаря в слабые ссылки. Сборщик мусора игнорирует слабые ссылки, т. е. объект, на который ведут только слабые ссылки, подлежит сборке в мусор. Например, в приведенном ниже коде не нужно удалять ключ myObject из myMap, чтобы объект можно было собрать в мусор:

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.