A fianco agli array tradizionali, le specifiche di ECMAScript 6 aggiungono nuove strutture dati al linguaggio arricchendolo di nuove potenzialità e di maggiore flessibilità. Si tratta dei Typed Array
, dei Set
e delle Map
.
Typed Array
I Typed Array
sono strutture dati che consentono la manipolazione efficiente di dati binari. Le specifiche prevedono due tipi di oggetto: ArrayBuffer
e ArrayBufferView
.
- ArrayBuffer è un oggetto che rappresenta un blocco di dati senza alcun formato specifico nè meccanismi per accedere al suo contenuto. Esso può essere pensato come una struttura dati per contenere una generica sequenza di byte.
- Il compito di consentire l'accesso al suo contenuto è affidato all'ArrayBufferView, oggetto che fornisce un tipo di dati e una struttura per interpretare i dati binari trasformandoli in un effettivo Typed Array.
L'oggetto ArrayBufferView in realtà non è un vero e proprio oggetto JavaScript, ma un nome per indicare diversi tipi di oggetto in base al modo in cui vogliamo interpretare i dati di buffer binario, eccone alcuni:
Oggetto | Tipo di dato |
---|---|
Int8Array |
per accedere ai dati come interi a 8 bit |
Uint8Array |
interi a 8 bit sensa segno (unsigned) |
Int32Array |
interi a 32 bit |
Il seguente esempio mostra come accedere ad un blocco di dati binari ed interpretarli come un array di interi a 32 bit:
var buffer = new ArrayBuffer(256);
var bufferView = new Int32Array(buffer);
buffer = fillBuffer();
for (var i=0; i<bufferView .length; i++) {
console.log("Elemento " + i + ": " + bufferView[i]);
}
Nell'esempio facciamo riferimento ad una generica funzione fillBuffer()
che si occupa di caricare dati binari nel buffer.
La disponbilità dei Typed Array
consente a JavaScript di poter manipolare a basso livello dati binari come ad esempio immagini, suoni ed altre risorse multimediali.
Set
Comunemente in JavaScript quando si ha bisogno di gestire insiemi di dati si fa ricorso agli array, ma non sempre questa struttura dati è comoda o sufficiente. ECMAScript 6 definisce strutture dati molto comode che evitano di inventarci artifici o di appoggiarci a routine ad hoc per fare operazioni abbastanza comuni.
Una di queste struttura dati è il Set, l'insieme. Un Set
può contenere dati di qualsiasi tipo ma senza duplicati.
Le operazioni più comuni che vengono fatte sugli insiemi sono l'aggiunta o la rimozione di elementi e la verifica dell'esistenza di un elemento. Analizziamo il seguente esempio:
var mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add("tre");
La prima istruzione crea un Set
mentre le istruzioni successive aggiungono alcuni elementi all'insieme tramite il metodo add().
Possiamo analizzare il contenuto di un Set sfruttando:
- la proprietà size, che indica il numero di elemento contenuti nella struttura dati
- il metodo has(), che indica se l'elemento passato come argomento è contenuto nell'insieme.
console.log(mySet.size); //3
console.log(mySet.has(2)); //true
Per eliminare un elemento da un Set utilizziamo il metodo delete() passandogli l'elemento da eliminare:
mySet.delete(1);
Il metodo clear(), infine, elimina tutti gli elementi contenuti nella struttura dati.
Map
Oltre agli insiemi abbiamo la possibilità di creare mappe associative che ci consentono di abbinare un valore ad una chiave. In realtà questo meccanismo è in qualche modo già intrinsecamente presente in JavaScript.
Infatti, come vedremo meglio più avanti, gli oggetti JavaScript non sono altro che coppie di chiavi e valori che ne rappresentano le proprietà. Tuttavia la mappa associativa implicita degli oggetti JavaScript prevede che la chiave, quindi il nome della proprietà, non possa essere qualcosa di diverso da una stringa.
La nuova struttura dati Map
, invece, consente di creare associazioni tra chiavi e valori di qualsiasi tipo, come possiamo vedere nel seguente esempio:
var myMap = new Map();
myMap.set("nome", "Mario");
myMap.set(3.14, "Pi greco");
var myObj = {id: 123, data: "test"};
myMap.set(myObj, "Oggetto");
Nell'esempio abbiamo creato la mappa ed aggiunto tre coppie chiave-valore tramite il metodo set()
. Come si può vedere, le chiavi, rappresentate dal primo argomento del metodo, possono essere di tipo diverso: stringhe, valori numerici, oggetti.
Analogamente agli insiemi, le mappe prevedono il metodo has() per verificare se una chiave esiste e delete() per eliminare un'associazione. La proprietà size consente di ottenere il numero degli elementi della mappa mentre get() consente di accedere al valore associato ad una chiave:
myMap.delete(3.14);
console.log(myMap.has(3.14)); //false
console.log(myMap.size); //2
console.log(myMap.get("nome")); //'Mario'
console.log(myMap.get(myObj)); //'Oggetto'
WeakMap
Una versione particolare di mappa associativa è rappresentata dalla WeakMap. Si tratta di una mappa simile alla Map
che abbiamo appena visto, ma i cui elementi sono gestiti tramite un riferimento debole che non impedisce al garbage collector di eliminarli dalla memoria.
In pratica è possibile che un elemento di una WeakMap
non sia più presente nella mappa senza una eliminazione esplicita da parte del codice, ma soltanto perché, non essendoci altri riferimenti attivi, il garbage collector
lo ha eliminato.
È evidente che questo tipo di mappa ha applicazioni del tutto particolari. Ad esempio può essere utilizzata mettendo in corrispondenza elementi del DOM, cioè della rappresentazione ad oggetti della struttura di una pagina HTML, con dei valori. Se in seguito a manipolazioni del DOM un elemento viene eliminato, la corrispondente associazione nella WeakMap
scompare di conseguenza.
È da sottolineare che le WeakMap
non ammettono chiavi di tipo semplice, come stringhe o numeri, ma soltanto oggetti.