JavaScript, uno dei linguaggi di programmazione più versatili, si è evoluto notevolmente negli anni. Questo approfondimento esplora in profondità le strutture dati Set
, Map
, WeakMap
, WeakSet
e alcuni operatori moderni, fornendo esempi pratici per una migliore comprensione.
Set
Il Set
in JavaScript è una collezione di elementi unici, che può contenere sia valori primitivi che oggetti.
Caratteristiche Dettagliate
- Unicità: Ogni valore in un
Set
è unico, il che elimina automaticamente i duplicati. - Accesso non indicizzato: A differenza degli array, i
Set
non permettono l'accesso diretto ai loro elementi tramite indici. - Metodi Utili:
.add(value)
: Aggiunge un valore alSet
..delete(value)
: Rimuove un valore specificato..has(value)
: Verifica se un valore è presente nelSet
.
Esempio Approfondito
1let numeri = new Set([2, 4, 6, 6, 8]);
2numeri.add(10); // Aggiunge 10
3numeri.delete(2); // Rimuove 2
4console.log(numeri.has(4)); // true
5
6// Iterazione su un Set
7for (let numero of numeri) {
8 console.log(numero); // Output: 4, 6, 8, 10
9}
Utilizzi Avanzati
- Rimozione efficace di duplicati da array.
- Implementazione di strutture dati come stack e code, dove l'unicità è fondamentale.
Map
Un Map
in JavaScript è una struttura dati che memorizza coppie chiave-valore, con chiavi uniche di qualsiasi tipo.
Caratteristiche Dettagliate
- Chiavi Versatili: A differenza degli oggetti, che hanno chiavi stringa, un
Map
può avere chiavi di qualsiasi tipo. - Ordine Mantenuto: A differenza degli oggetti, i
Map
mantengono l'ordine di inserimento delle chiavi. - Metodi Fondamentali:
.set(key, value)
: Aggiunge o aggiorna una coppia chiave-valore..get(key)
: Ritorna il valore associato a una chiave..has(key)
: Verifica se una chiave è presente nelMap
.
Esempio Approfondito
1let mappa = new Map();
2mappa.set('nome', 'Alice');
3mappa.set('età', 25);
4
5console.log(mappa.get('nome')); // "Alice"
6console.log(mappa.size); // 2
7
8// Iterazione su una Map
9for (let [chiave, valore] of mappa) {
10 console.log(`${chiave}: ${valore}`); // "nome: Alice", "età: 25"
11}
Utilizzi Avanzati
- Gestione efficiente di dati strutturati.
- Implementazione di cache per memorizzare e recuperare dati velocemente.
WeakMap
Un WeakMap
è una variante speciale di Map
in cui tutte le chiavi sono oggetti e sono debolmente referenziate.
Caratteristiche Dettagliate
- Chiavi Deboli: Le chiavi in un
WeakMap
sono oggetti e non impediscono al garbage collector di rimuovere questi oggetti quando non sono più referenziati altrove. - Non Enumerabile: A differenza di
Map
, non è possibile elencare le chiavi di unWeakMap
. - Uso della Memoria: Migliorato per la gestione di grandi quantità di dati.
Esempio Approfondito
1let weakMap = new WeakMap();
2let oggetto = { id: 1 };
3weakMap.set(oggetto, 'informazioni aggiuntive');
4
5console.log(weakMap.get(oggetto)); // "informazioni aggiuntive"
6oggetto = null; // Lascia che il garbage collector rimuova l'oggetto se non è referenziato altrove
#
Utilizzi Avanzati
- Ottimale per memorizzare dati privati associati a un oggetto.
- Utilizzato in librerie e framework per mantenere metadati senza influire sul ciclo di vita degli oggetti.
WeakSet
Un WeakSet
è un insieme di oggetti con riferimenti deboli.
Caratteristiche Dettagliate
- Solo Oggetti: Può contenere solamente oggetti, non valori primitivi.
- Riferimenti Deboli: Gli oggetti in un
WeakSet
possono essere rimossi dal garbage collector se non sono più referenziati. - Non Iterabile: A differenza di
Set
, non è possibile iterare attraverso unWeakSet
.
Esempio Approfondito
1let weakSet = new WeakSet();
2let oggetto1 = { nome: 'oggetto1' };
3weakSet.add(oggetto1);
4
5console.log(weakSet.has(oggetto1)); // true
6oggetto1 = null; // L'oggetto può essere rimosso dal garbage collector
Utilizzi Avanzati
- Gestione di collezioni di oggetti senza influenzare il garbage collection.
- Utilizzato in contesti dove si desidera evitare perdite di memoria per riferimenti non necessari.
Operatori Moderni
JavaScript offre una varietà di operatori moderni per semplificare le operazioni comuni.
Destructuring Assignment
Permette di scomporre array e oggetti assegnando le loro parti a variabili distinte.
Esempio Avanzato
1let [a, , c] = [1, 2, 3]; // 'a' è 1, 'c' è 3
2let { nome, età } = { nome: 'Alice', età: 25, lavoro: 'Ingegnere' }; // 'nome' è 'Alice', 'età' è 25
Spread Operator (...
)
Espande elementi di array o oggetti in nuovi contesti.
Esempio Avanzato
1let parteIniziale = [1, 2];
2let arrayCompleto = [...parteIniziale, 3, 4]; // [1, 2, 3, 4]
3let oggetto = { nome: 'Alice', età: 25 };
4let copiaOggetto = { ...oggetto, lavoro: 'Ingegnere' }; // { nome: 'Alice', età: 25, lavoro: 'Ingegnere' }
Rest Operator (...
)
Raccoglie elementi in un array, specialmente in funzioni con un numero variabile di argomenti.
Esempio Avanzato
1function unisciStringhe(separator, ...stringhe) {
2 return stringhe.join(separator);
3}
4console.log(unisciStringhe("-", "Alice", "Bob", "Charlie")); // "Alice-Bob-Charlie"
Operatori Logici Avanzati
Operatore AND Logico (&&
)
L'operatore &&
ritorna il valore del primo operando se è falsy (valore che equivale a false, come 0
, null
, undefined
, false
, NaN
, o una stringa vuota), altrimenti ritorna il valore del secondo operando. Questo comportamento è noto come "short-circuiting".
Esempio
1let risultato = 0 && "test"; // 0, perché il primo operando è falsy
2let nome = "Alice" && "Bob"; // "Bob", perché il primo operando è truthy
Operatore OR Logico (||
)
L'operatore ||
ritorna il valore del primo operando se è truthy, altrimenti ritorna il valore del secondo operando. Anche questo comporta un "short-circuiting".
Esempio
1let risultato = 0 || "test"; // "test", perché il primo operando è falsy
2let nome = "Alice" || "Bob"; // "Alice", perché il primo operando è truthy
Operatore Nullish Coalescing (??
)
Questo operatore ritorna il secondo operando solo quando il primo è null
o undefined
, altrimenti ritorna il primo. È utile per assegnazioni predefinite.
Esempio
1let valore;
2let defaultValore = valore ?? "predefinito"; // "predefinito", perché valore è undefined
3valore = 0;
4defaultValore = valore ?? "predefinito"; // 0, perché valore è definito (anche se falsy)
Concatenazione Opzionale
La concatenazione opzionale (?.
) permette di accedere in modo sicuro alle proprietà di un oggetto che potrebbe non esistere. Se l'oggetto prima dell'operatore ?.
è null
o undefined
, l'espressione si interrompe e ritorna undefined
, altrimenti procede normalmente.
Esempio
1let oggetto = { a: { b: { c: 1 } } };
2let valoreC = oggetto.a?.b?.c; // 1, perché oggetto.a e oggetto.a.b esistono
3let valoreInesistente = oggetto.a?.b?.d; // undefined, perché oggetto.a.b.d non esiste
4
5// Senza l'uso di concatenazione opzionale, potrebbe essere generato un errore
6// let errore = oggetto.a.b.d; // TypeError se oggetto.a o oggetto.a.b non esistono
Utilizzi Avanzati
- Accesso sicuro a catene di proprietà profonde in oggetti.
- Riduzione del rischio di errori di tipo
TypeError
in accessi a proprietà di oggetti non definiti.
Gli operatori logici &&
, ||
, ??
, insieme alla concatenazione opzionale ?.
, offrono strumenti potenti per scrivere codice più sicuro, leggibile e conciso. Essi consentono di gestire in modo elegante situazioni in cui i dati potrebbero essere incompleti o incerti, che sono comuni nella programmazione di applicazioni reali.
Caricamento...
Diventiamo amici di penna? ✒️
Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.
Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!