Vai al contenuto principale

Operatori e strutture dati moderni in JavaScript

Esplora le strutture dati avanzate in JavaScript - Set, Map, WeakSet, WeakMap - e gli operatori moderni (&&, ||, ??) con esempi pratici e dettagliati.

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 al Set.
    • .delete(value): Rimuove un valore specificato.
    • .has(value): Verifica se un valore è presente nel Set.

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 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 nel Map.

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 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 un WeakMap.
  • 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 WeakSet possono essere rimossi dal garbage collector se non sono più referenziati.
  • Non Iterabile: A differenza di Set, non è possibile iterare attraverso un WeakSet.

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 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.

Unisciti a WebTea

Niente spam. Solo contenuti formativi su Software Engineering.

Ci sono due cose che non ci piacciono: lo spam e il mancato rispetto della privacy. Seleziona come vuoi restare in contatto:

Preferenze di contatto

Usiamo Mailchimp come piattaforma di marketing. Cliccando su iscriviti, accetti la nostra privacy policy e che le tue informazioni vengano trasferite a Mailchimp per l'elaborazione. Termini e Privacy. Puoi disiscriverti in qualsiasi momento.