Tra le novità introdotte nel Flash Player 10 (e nella CS4), se ne annovera una molto interessante per gli sviluppatori, benchè poco conosciuta e "pubblicizzata": si tratta del tipo di oggetto Vector, che può essere considerato un "parente" dell'Array
e che, in molti casi, può sostituirlo con miglioramenti, anche notevoli, a livello di performance.
In questo articolo esaminiamo i punti in comune e le princiapli differenze tra Vector
ed Array
.
Nota: l'oggetto Vector
è disponibile solo in ActionScript 3 ed è compatibile solo con il Flash Player 10 e successivi.
Dichiarazione della variabile
La differenza più importante tra questi i due tipi risiede nel fatto che Array può contenere diversi tipi di oggetti, mentre Vector può contenere oggetti solo di un tipo (quindi solo numeri, o solo stringe, o solo Sprite, etc.) e questo tipo va specificato in fase di dichiarazione. Se per dichiarare un array è sufficiente la sintassi:
var array:Array = new Array()
Nella dichiarazione di un vettore bisogna specificare il tipo di oggetto, in questo modo:
var vettore:Vector.<Number> = new Vector.<Number>()
In questo caso abbiamo definito un vettore con elementi di solo tipo numerico. Vediamo meglio cosa comporta questa differenza: usando un Array
, possiamo scrivere un codice simile a questo:
var array:Array = new Array(); array[0] = "Ciao"; array[1] = 0; array[2] = root;
Non riceveremo errori di compilazione, e otterremo una collezione di tre diversi tipi di oggetto: una stringa ("ciao"
), un numero (0
) e un oggetto DisplayObject
(il riferimento a root
).
Una operazione del genere non è possibile con un Vector
dichiarato di tipo Number
e, lanciando il codice seguente:
var vettore:Vector.<Number> = new Vector.<Number>(); vettore[0] = "Ciao"; vettore[1] = 0; vettore[2] = root;
otterremo due errori di compilazione, uno per l'elemento stringa e uno per l'elemento DisplayObject
, perchè il contenuto accettato da vettore
deve essere esclusivamente numerico.
Ovviamente, oltre ai tipi del Flash Player, si può specificare come oggetto una classe personalizzata.
var vettore:Vector.<Classe> = new Vector.<Classe>();
Indici e lunghezza dell'oggetto
Un'altra differenza di cui tenere conto è una limitazione nell'uso degli indici: un Vector non può avere indici vuoti, cosa invece possibile per gli Array
. Anche in questo caso facciamo un piccolo esempio per capire meglio.
var array:Array = new Array(); array[0] = "Ciao"; array[2] = root;
Questo codice sarà compilato senza errori, e se proviamo a stampare il valore dell'indice 1 di array
otteniamo il valore undefined
. Se invece proviamo questo codice:
var vettore:Vector.<Number> = new Vector.<Number>(); vettore[0] = 1; vettore[2] = 3;
Otterremo un errore RangeError: Error #1125: L'indice 2 non è nell'intervallo 1
.
Il concetto è simile a quello della DisplayList
, in ActionScript 3 non possiamo usare indici arbitrari per impostare la profondità di un movieclip
o di uno sprite
, ma è necessario procedere in ordine: lo stesso vale per un Vector
, dove gli indici devono essere consecutivi.
Un'altra caratteristica che i Vector
hanno, rispetto agli Array
, è la possibilità di dichiarare il numero degli elementi ed eventualmente renderlo fisso. Ad esempio in questo frammento di codice:
var vettore:Vector.<Number> = new Vector.<Number>(3); vettore[0] = 1; vettore[2] = 3;
dichiariamo un vettore
numerico di 3 elementi (quindi con indici 0, 1 e 2). Inoltre non abbiamo errori, poiché l'elemento vettore[1]
esiste ed è impostato a 0
. Se invece avessimo come tipo di oggetto String
il valore all'indice 1 sarebbe undefined
.
Dichiarando il numero di elementi, quindi, popoliamo il vettore di n
indici, ovviamente eventuali nuovi indici dovranno essere consecutivi ai precedenti, ad esempio nel codice di prima potremmo creare l'elemento vettore[3]
, ma non vettore[4]
.
// codice accettato e funzionante var vettore:Vector.<Number> = new Vector.<Number>(3); vettore[0] = 1; vettore[1] = 3; vettore[3] = 5; // genera un errore var vettore:Vector.<Number> = new Vector.<Number>(3); vettore[0] = 1; vettore[1] = 3; vettore[4] = 5;
Il fatto che venga accettata l'aggiunta di valore[3]
, sebbene abbiamo dichiarato la dimensione dell'oggetto Vector, indicha che tale dimensione è dinamica e può variare durante l'esecuzione.
Come abbiamo accennato è anche possibile impostare l'oggetto in modo che il vettore abbia la lunghezza fissa, in questo modo:
var vettore:Vector.<Number> = new Vector.<Number>(3, true);
In questo caso vettore
non potrà avere più di tre elementi: possiamo quindi sovrascrivere senza problemi quelli da 0 a 2 (rispettando il tipo impostato, in questo caso Number
), ma non ci è consentito di aggiungere né rimuovere elementi.
La lunghezza fissa su un vettore si può attivare o disattivare anche in seguito grazie alla proprietà fixed
// disattiva la lunghezza fissa per il vettore vettore.fixed = false;
Chiavi testuali
Un'altra differenza sta nel fatto che Vector supporta solo indici numerici e non testuali. Per esempio possiamo popolare un Array
in questo modo:
var array:Array = new Array(); array["ciao"] = "Ciao"; array["root"] = root;
Con Vector
questo non è possibile. Volendo potremmo creare un Vector
di Array
o di Object
, in questo modo:
var vettore:Vector.<Array> = new Vector.<Array>(); vettore[0] = new Array(); vettore[0]["ciao"] = "ciao"; vettore[0]["root"] = root;
ma, nella maggior parte dei casi, è un'operazione priva di senso. Possiamo considerare Vector
come alternativa ad Array
quando si utilizza un solo tipo di oggetto.
Ordinamento dei valori
Un altro punto in cui queste due tipologie di oggetto sono sostanzialmente differenti è l'ordinamento degli elementi: sebbene il comando usato sia sempre sort
, nel caso di Vector è sempre necessario specificare una funzione di comparazione personalizzata. È una possibilità che si ha anche con Array
, tuttavia per questi ultimi esistono anche funzioni di ordinamento predefinite, invece se proviamo da applicare il comando sort
su un Vector
, questo non viene ordinato ma ne viene solo creata una copia identica.
Vediamo allora come usare una funzione personalizzata, per prima cosa creiamo il nostro Vector
che per semplificare faremo di tipo numerico.
var numeri:Vector.<Number> = new Vector.<Number>(); numeri.push(12, 27, 13.6, 94.4, 219, -3234, 0.09);
Scriviamo quindi il codice per la comparazione:
var ordinato:Vector.<Number> = numeri.sort(ordinaNumerico); trace(ordinato); function ordinaNumerico(x:Number, y:Number):Number { if (x < y) { return -1; } else if (x > y) { return 1; } else { return 0; } }
Il vettore risulterà ordinato in ordine crescente, poiché nel caso di x<y
il valore ritornato è -1
, mentre il comparatore ritorna il valore 1
se x>y
. È facile intuire che possiamo invertire l'ordinamento invertendo questi due valori.
Punti in comune tra Array e Vector
Finora abbiamo visto le differenza tra array e vector, ma questi due tipi di oggetto hanno molti punti in comune, principalmente per quanto riguarda la manipolazione e le proprietà.
Aggiunta di uno o più elementi
Ad esempio, per aggiungere oggetti abbiamo a disposizione per entrambi i comandi push e unshift (oltre alla notazione [indice]
). Attenzione però, l'uso di questi due comandi con Vector nasconde un'insidia: il tipo dell'elemento che aggiungiamo alla collezione viene verificato solo a runtime. Ad esempio, il codice
var vettore:Vector.<Number> = new Vector.<Number>(); vettore[0] = 2; vettore[1] = 4; vettore[2] = "ciao"; trace(vettore[2]);
restituisce un errore di compilazione rilevando il tipo di valore stringa di "ciao", mentre il codice
var vettore:Vector.= new Vector. (); vettore[0] = 2; vettore[1] = 4; vettore.push("ciao"); trace(vettore[2]);
viene eseguito senza errori, anche se poi come output otterremmo NaN
(Not a Number) poichè il valore "ciao", non essendo numerico, verrebbe inserito in maniera errata nel Vector. Facciamo quindi attenzione ad usare questi comandi solo quando siamo sicuri del tipo di dati che verrà inserito, o comunque inserendo dei controlli a riguardo.
Ricavare il valore di un elemento
Come abbiamo visto, per ricavare un valore da un vettore e da un array si utilizza la notazione con le parentesi quadre. È possibile usare anche i metodi pop e shift, che rispettivamente ricavano e rimuovono l'ultimo e il primo elemento di un Array
o di un Vector
.
Ricavare il numero di elementi nell'oggetto
Anche in questo caso la proprietà da utilizzare è la medesima, infatti length
vale sia per Array
, sia per Vector
, va considerato però che per Vector
il valore è per certi versi "più attendibile" data l'impossibilità di usare indici "fuori intervallo", mentre con un array questo codice:
var array:Array = new Array(); array[0] = 0; array[5] = 1; trace(array.length)
restituisce come output 6, quando in realtà abbiamo solo due elementi nel nostro array. Con Vector
questo non accadrebbe, a meno che non si sia specificata nel costruttore la lunghezza.
Ricerca di elementi e manipolazione dell'oggetto
Tanto per un Array quanto per un Vector, è possibile usare i metodi IndexOf
e lastIndexOf
; analogamente, i comandi every
, some
, forEach
, map
e filter
sono disponibili per entrambi i tipi di oggetto e hanno funzionamento identico.
Conclusioni
Array
e Vector
sono molto simili. Potremmo dire che Vector
sia una sorta "mutazione" di Array
: ne eredita pressoché tutti i comandi e ne varia leggermente le caratteristiche, principalmente il fatto di poter contenere oggetti di un solo tipo. Questa potrebbe apparire una limitazione, ma è in realtà ciò che rende l'oggetto Vector
molto interessante: grazie a queste restrizioni Vector offre maggior sicurezza e soprattutto migliori prestazioni. Da alcuni test di performance emerge un miglioramento della velocità di esecuzione anche del 60% rispetto ad Array.
L'unico caso in cui attualmente sembra che i Vector siano più lenti sono le operazioni di ordinamento, nelle altre operazioni invece Vector
risulta più veloce e spesso in maniera rilevante, aspetto che lo rende sicuramente molto utile nello sviluppo di applicazioni che prevedono molti calcoli.