52 Oggetti nativi map e set

map e set sono due strutture dati introdotte con Ecma Script 6.

Map rappresenta un’efficiente implementazione dei cosìddetti array associativi comuni in diversi linguaggi di programmazione. Nei classici array, come sappiamo, la chiave di accesso è rappresentata dalla posizione (0,1,2,3…) implementando il vettore della posizione zero, il vettore di uno, vettore di due….

Map come oggetto generalizza il concetto di chiave, consentendo di utilizzare qualunque cosa, a quella chiave abbina il suo valore.

Creo un nuovo oggetto Map

let capitali = new Map();

Ora con il metodo set, assegno i valori, specificando la coppia chiave / valore

capitali.set("Italia", "Roma");
capitali.set("Francia", "Parigi");

è possibile sfruttare anche il chaining:

new Map()
    .set("it","Roma")
    .set("fr","Parigi")

Avremo una serie di stati con le loro capitali, il punto di forza del Map è che potremo andare a cercare un valore specificando la key (chiave)

nazione_richiesta = prompt("Quale nazione?");

Chiedo all’utente la nazione poi faccio un controllo se è in elenco tramite il metodo has e se contiene la nazione inserita dall’utente

if ( capitali.has(nazione_richiesta) )

se viene trovato il riscontro stampo il risultato utilizzando il metodo get, prendi, estraendo il dato, altrimenti restituisco un messaggio di corrispondenza non trovata

if ( capitali.has(nazione_richiesta) )
{ writeln(`La capitale è ${capitali.get(nazione_richiesta)}`);}
else
{ writeln("Nazione non trovata");}

aggiungere diversi elementi tramite il set, potrebbe risultare tedioso, esiste una tecnica più efficiente che consiste nel fornire al costruttore come parametro un oggetto iterabile, tipo un array, anche sotto forma di costante letterale come faremo in questo esempio

let capitali = new Map([ 
  ["Italia", "Roma"],
  ["Francia", "Parigi"], 
  ["Inghilterra", "Londra"]
]);

attenzione alle doppie parentesi, quindi per ogni elemento dell’array, dichiaro un sotto array nella forma chiave/valore.

Esiste anche delete(), un metodo per eliminare un elemento dalla Map.  Nell’esempio se la nazione esiste la elimino

if ( capitali.has(nazione_richiesta) )
{ 
  capitali.delete(nazione_richiesta);
  writeln(`${nazione_richiesta} eliminata ...`);}
else
{ writeln("Nazione non trovata");}

Oggetti come chiavi

Nelle chiavi non siamo limitati a fornire solo stringhe e numeri, ma anche oggetti, anche complessi:

let listino = new Map();
let prodotto = { 
  codice: 100, 
  descrizione: {breve: "bla bla", lunga:"bla bla bla bla"}
}

Abbiamo creato una mappa listino e poi abbiamo preparato l’oggetto prodotto che fungerà da chiave, le proprietà sono codice e descrizione che è un sotto oggetto che a sua volta ha le proprietà breve e lunga. Alla chiave prodotto vogliamo associare uno scema di costo rappresentato dall’oggetto prezzo

let prezzo = { 
  costo_base: 145,
  sconto: 5, 
  metodi_pagamento: {cash: true, carta: true, paypal: false}
}

aggiungiamo la seguente coppia al listino

listino.set( prodotto, prezzo);

le operazioni svolte prima sono dimili a quelle da utilizzare ora, solo useremo gli oggetti

if ( listino.has(prodotto) )
{
   valore = listino.get(prodotto);
   writeln(valore.costo_base);
   if (valore.metodi_pagamento.carta)
   {writeln("Pagabile con carta di credito")}
}

se nella mappa listino è presente (has) il prodotto, allora estraggo il valore col get stampo il valore del costo_base, oppure potrei sfruttare il destructuring visto nella precedente lezione. Infine un’ulteriore conferma se sia possibile pagare con la carta di credito.

Abbiamo anche la possibilità di sapere quanti elementi sono presenti in un certo momento in una mappa tramite la property size .

writeln(`Ci sono ${capitali.size} nazioni in archivio`);

Con il metodo clear è possibile eliminare tutto il contenuto da una mappa, lanciamolo e riconfermiamo col size

capitali.clear();
writeln(`Ci sono ${capitali.size} nazioni in archivio`);

Iterare sulle mappe

Innanzitutto possiamo iterare sugli elementi tramite un classico ciclo for of

for (let elemento of capitali)
{ writeln(elemento); }

elemento, ad ogni iterazione, andrà ad assumere il valore di ciascun elemento, cioè la coppia nome nazione/capitale, essendo un array è facile intuire che sull’indice 0 avrò la nazione e su 1 la capitale

elemento[0]=nazione, [1]=capitale

abbiamo poi il metodo keys() che è un iteratole sulle chiavi, che nel nostro caso sono i nomi delle nazioni

for (let chiave of capitali.keys())
{ writeln(chiave); }

Non dimentichiamoci del destructuring  che ci permette di avere 2 variabili belle pronte all’uso contenenti le chiavi e i valori. Ne approfittiamo per introdurre il metodo entries() che è l’iteratole predefinito

for (let [chiave, valore]  of listino.entries())
{ writeln(chiave); }

entries() è associato alla property Symbol.iterator, è l’ iteratore standard ecco perché ha funzionato senza problemi nel ciclo for of precedente quando si è cercato of capitali e il ciclo va ha cercare se esiste un iteratole standard che è proprio entries(). Di fatto sia il ciclo di prima che questo sono equivalenti ed il primo è chiaramente più snello, quindi preferibile, di conseguenza diventa:

for (let [chiave, valore]  of listino))
{ writeln(chiave); }

La chiave, essendo un oggetto complesso, porta a restituire solo che è un oggetto, se procedo alla stampa brutale come abbiamo fatto nell’esempio, quindi in realtà bisogna estrarne il contenuto dalla chiave composita

Set

il set è l’insieme, concettualmente molto simile al map.

let nazioni = new Set(["Italia", "Francia", "Inghilterra"]);
nazioni.add("Ungheria");

ad una prima occhiata potrebbe sembrare un array classico con un metodo add() che aggiunge un elemento, anziché quello tipico degli array push(), in realtà ci sono delle differenze, prima tra tutte, il set rifiuta in automatico i doppioni.

nazioni.add("Francia");

questo comando non serve a nulla, l’elemento Francia non verrà aggiunto perché già presente, la conferma l’avremo con l’iterazione e la stampa del set

for (let nazione of nazioni)
{writeln(nazione);}

Il set è dunque molto utile nei casi in cui è necessario tenere una lista univoca di elementi.

Anche i set hanno a disposizione come i map i metodi: .size, .has() e .clear().

Spread operator

Lo spread operator è un potente generatore di array (e di qualunque oggetto iterabile). Visto che il set a differenza degli array non contiene indici, per scegliere dei particolari valori, dovremmo iterarlo ed elaborare i tutti i dati, contandoli, per poi prendere quelli che ci interessano. Diventa particolarmente interessante convertire i set e i map in un array tramite lo spread operator che si rappresenta, come il rest, con i 3 punti … quando usato tra parentesi quadre aggiungerà i valori dell’elemento iterabile ad un array

let vNazioni = [...nazioni];

Dopo questa istruzione, avremo un vettore identificato con vNazioni contenente tutti gli elementi del set nazioni.

A questo non avremo nessuno problema a chiedere il valore del suo terzo elemento, per esempio

writeln(vNazioni[2]);

Esistono delle versioni di map e set chiamate weakMap e WeakSet che hanno a che fare col rilascio della ram degli elementi che occupano e alla loro allocazione con riferimento debole che ne impedisce la cancellazione dalla memoria.

Altri argomenti non trattati in questa guida sono i typed array e l’endianess dei byte, le espressioni regolari, i moduli, gli eventi e manipolazione del DOM, la programmazione asincrona (AJAX), le promises.

Ecco alcune risorse utili per reperire informazioni

Il libro del Dr. Axel Rauschmayer : Exploring ES6 e il sito annesso 2ality.com

autorevole il sito Eric Elliot nonché il faro per gli sviluppatori stack overflow e il social Quora e chiudendo con la fonte autorevole di mozilla developer network

Crediti

infine non può mancare il mentore dal quale è stata tratta questa guida, il prof. F. Camuso che ringrazio.

Ecco il sito ed il suo canale Yotube , iscrivetevi !!!