Operatore di coalescenza nullish in JavaScript (??)
Impara l'operatore nullish coalescing (??), le differenze con ||, la precedenza e gli operatori di assegnazione logica ??=, &&= e ||=.
L'operatore di coalescenza nullish (??) è un modo conciso ed espressivo per fornire un valore predefinito in JavaScript. Restituisce l'operando destro solo quando l'operando sinistro è nullish — ovvero null o undefined — e in caso contrario restituisce il valore sinistro invariato. Introdotto in ES2020, risolve un problema di lunga data legato all'uso dell'operatore || per i valori predefiniti, e funziona perfettamente insieme a optional chaining e agli operatori logici che già conosci.
Cosa Significa "Nullish"
Un valore è considerato nullish quando è esattamente null o undefined. Qualsiasi altro valore — compresi i valori falsy come 0, '', false e NaN — viene trattato da ?? come un valore reale e intenzionale.
null ?? 'default' // 'default'
undefined ?? 'default' // 'default'
0 ?? 'default' // 0
'' ?? 'default' // ''
false ?? 'default' // false
NaN ?? 'default' // NaNLa regola è semplice: se il lato sinistro è null o undefined, si ottiene il lato destro; altrimenti si ottiene il lato sinistro.
Come ?? Differisce da ||
Questa è la ragione più importante per cui esiste ??. L'operatore OR logico (||) restituisce il lato destro ogni volta che il lato sinistro è un qualsiasi valore falsy — 0, '', false, NaN, null e undefined rientrano tutti in questa categoria. Tale comportamento va bene finché 0 o una stringa vuota non rappresentano un valore legittimo, nel qual caso || produce silenziosamente un risultato errato.
Considera un contatore il cui valore valido può essere 0:
let count = 0;
let withOr = count || 100; // 100 — wrong! 0 got replaced
let withNullish = count ?? 100; // 0 — correct, 0 was preservedPoiché 0 è falsy, || lo tratta come "nessun valore" e ricade su 100. L'operatore ?? riconosce che 0 non è nullish e lo mantiene. La stessa trappola si applica alle stringhe vuote:
Usa ?? al posto di || ogni volta che 0, '' o false sono input validi. Usare || per i valori predefiniti in questi casi è una delle fonti più comuni di bug sottili in JavaScript — ad esempio, una quantità pari a 0 che diventa 1, o un campo di ricerca vuoto che acquisisce un testo segnaposto.
Precedenza e Parentesi
L'operatore ?? ha bassa precedenza — circa lo stesso livello di || e inferiore agli operatori aritmetici e di confronto. In pratica questo significa che il fallback viene risolto prima che il valore venga usato in un'espressione più grande, ma dovresti comunque raggruppare con le parentesi per mantenere chiara l'intenzione.
let height = null;
let width;
// Each ?? is evaluated, then the products are multiplied
let area = (height ?? 100) * (width ?? 50);
console.log(area); // 100 * 50 = 5000Senza le parentesi la moltiplicazione si legherebbe più strettamente di quanto potresti aspettarti, quindi racchiudere ogni valore predefinito in ( ... ) rende il calcolo non ambiguo e leggibile.
Combinare ?? con && o || È Vietato
JavaScript vieta esplicitamente di mescolare ?? con && o || nella stessa espressione senza parentesi. Farlo genera un SyntaxError, perché la precedenza tra di essi sarebbe ambigua e facile da interpretare erroneamente.
// SyntaxError: Unexpected token '||'
let result = a ?? b || c;
// Fix it by grouping explicitly:
let safe = (a ?? b) || c; // valid
let other = a ?? (b || c); // also valid, different meaningLe due forme valide hanno significati diversi, ed è esattamente per questo che il linguaggio ti obbliga a scegliere. Aggiungi le parentesi e indica con precisione cosa intendi.
La restrizione si applica solo quando ?? si trova direttamente accanto a && o ||. Puoi usarli liberamente in espressioni separate, e le parentesi risolvono sempre l'ambiguità.
Operatori di Assegnazione Logica
ES2021 ha introdotto tre operatori di assegnazione logica che abbinano un'assegnazione a un controllo logico. Assegnano alla variabile sinistra solo quando una condizione è soddisfatta, il che li rende ideali per impostare valori predefiniti e aggiornamenti condizionali.
Assegnazione Nullish (??=)
x ??= y assegna y a x solo se x è attualmente null o undefined. È la forma di assegnazione di ?? ed è il più comune dei tre per impostare valori predefiniti su un object.
let settings = { theme: 'dark' };
settings.theme ??= 'light'; // already set → stays 'dark'
settings.fontSize ??= 16; // missing → becomes 16
console.log(settings); // { theme: 'dark', fontSize: 16 }Assegnazione OR Logico (||=)
x ||= y assegna y a x quando x è falsy (0, '', false, null, undefined, NaN). Come ||, può sovrascrivere valori falsy validi, quindi usalo solo quando un valore falsy significa davvero "sostituiscimi".
Assegnazione AND Logico (&&=)
x &&= y assegna y a x solo quando x è truthy. È utile per aggiornare un valore che già esiste senza crearlo.
let config = { token: 'abc123' };
config.token &&= config.token.trim(); // truthy → trimmed and reassigned
config.missing &&= 'never set'; // undefined → left untouched
console.log(config); // { token: 'abc123' }Ogni operatore effettua anche un cortocircuito: valuta e assegna il lato destro solo quando la condizione lo richiede, quindi gli effetti collaterali sul lato destro vengono saltati quando l'assegnazione non avviene.
Casi d'Uso Reali
L'operatore ?? eccelle ovunque un valore potrebbe legittimamente essere assente mentre 0 o '' devono essere rispettati. Scenari tipici includono la lettura di configurazioni, l'impostazione di valori predefiniti per parametri di funzione opzionali e il recupero di campi da risposte API.
// 1. Default options merged with user input
function createButton(options) {
let label = options.label ?? 'Submit';
let count = options.count ?? 0; // 0 stays 0, never becomes a default
return { label, count };
}
// 2. Reading a possibly-missing API field
let response = { data: { user: { nickname: null } } };
let name = response.data.user.nickname ?? 'Guest';
console.log(name); // 'Guest'Si abbina particolarmente bene all'optional chaining (?.). L'optional chaining restituisce in modo sicuro undefined quando parte di un percorso è assente, e ?? fornisce il fallback in un'unica riga pulita:
let city = user?.address?.city ?? 'Unknown';Si legge come: "Usa la città dell'utente se l'intera catena esiste, altrimenti usa 'Unknown'." Per decidere quale dei due percorsi seguire in base a una condizione, l'operatore condizionale (ternario) rimane lo strumento migliore — ?? serve specificamente per fornire valori predefiniti per valori nullish.
Supporto browser: ?? fa parte di ES2020 e gli operatori di assegnazione logica (??=, ||=, &&=) sono arrivati in ES2021. Tutti i browser moderni e Node.js 14+ li supportano. Se devi supportare ambienti molto vecchi, un transpiler come Babel può compilarli.
Riepilogo
??restituisce l'operando destro solo quando il sinistro ènulloundefined; altrimenti restituisce il sinistro.- Preferisci
??rispetto a||per i valori predefiniti quando0,''ofalsesono valori validi. ??ha bassa precedenza — raggruppa con le parentesi, e non collocarlo mai direttamente accanto a&&o||senza parentesi (ciò genera unSyntaxError).??=,||=e&&=assegnano in modo condizionale: rispettivamente su nullish, su falsy e su truthy.- Combina
??con optional chaining (?.) per leggere dati potenzialmente assenti e fornire un valore predefinito in un'unica espressione.