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
Setnon 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
let numeri = new Set([2, 4, 6, 6, 8]);
numeri.add(10); // Aggiunge 10
numeri.delete(2); // Rimuove 2
console.log(numeri.has(4)); // true
// Iterazione su un Set
for (let numero of numeri) {
console.log(numero); // Output: 4, 6, 8, 10
}
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
Mappuò avere chiavi di qualsiasi tipo. - Ordine Mantenuto: A differenza degli oggetti, i
Mapmantengono 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
let mappa = new Map();
mappa.set('nome', 'Alice');
mappa.set('età', 25);
console.log(mappa.get('nome')); // "Alice"
console.log(mappa.size); // 2
// Iterazione su una Map
for (let [chiave, valore] of mappa) {
console.log(`${chiave}: ${valore}`); // "nome: Alice", "età: 25"
}
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
WeakMapsono 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
let weakMap = new WeakMap();
let oggetto = { id: 1 };
weakMap.set(oggetto, 'informazioni aggiuntive');
console.log(weakMap.get(oggetto)); // "informazioni aggiuntive"
oggetto = 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
WeakSetpossono essere rimossi dal garbage collector se non sono più referenziati. - Non Iterabile: A differenza di
Set, non è possibile iterare attraverso unWeakSet.
Esempio Approfondito
let weakSet = new WeakSet();
let oggetto1 = { nome: 'oggetto1' };
weakSet.add(oggetto1);
console.log(weakSet.has(oggetto1)); // true
oggetto1 = 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
let [a, , c] = [1, 2, 3]; // 'a' è 1, 'c' è 3
let { 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
let parteIniziale = [1, 2];
let arrayCompleto = [...parteIniziale, 3, 4]; // [1, 2, 3, 4]
let oggetto = { nome: 'Alice', età: 25 };
let 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
function unisciStringhe(separator, ...stringhe) {
return stringhe.join(separator);
}
console.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
let risultato = 0 && "test"; // 0, perché il primo operando è falsy let 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
let risultato = 0 || "test"; // "test", perché il primo operando è falsy let 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
let valore; let defaultValore = valore ?? "predefinito"; // "predefinito", perché valore è undefined valore = 0; defaultValore = 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
let oggetto = { a: { b: { c: 1 } } };
let valoreC = oggetto.a?.b?.c; // 1, perché oggetto.a e oggetto.a.b esistono
let valoreInesistente = oggetto.a?.b?.d; // undefined, perché oggetto.a.b.d non esiste
// Senza l'uso di concatenazione opzionale, potrebbe essere generato un errore
// 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
TypeErrorin 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.