Esiste un operatore "null coalescing" in JavaScript?


1381

Esiste un operatore null coalescente in Javascript?

Ad esempio, in C #, posso fare questo:

String someString = null;
var whatIWant = someString ?? "Cookies!";

La migliore approssimazione che riesco a capire per Javascript sta usando l'operatore condizionale:

var someString = null;
var whatIWant = someString ? someString : 'Cookies!';

Che è una specie di imho malizioso. Posso fare di meglio?


31
nota dal 2018: la x ?? ysintassi è ora nello stato della proposta della fase 1 - coalescenza
nulla

2
Ora c'è un plug-in Babel che incorpora questa sintassi esatta.
Jonathan Sudiaman,

10
Nota dal 2019: ora è lo stato della fase 3!
Daniel Schaffer,

3
Nota da gennaio 2020: l'operatore di coalescenza Nullish è disponibile in modo nativo in Firefox 72 ma l'operatore di concatenamento opzionale non lo è ancora.
Kir Kanos

4
L'operatore di coalescenza nullish ( x ?? y) e l'operatore di concatenamento opzionale ( user.address?.street) sono ora entrambi Stage 4. Ecco una buona descrizione di ciò che significa: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net,

Risposte:


2135

Aggiornare

JavaScript ora supporta l' operatore di coalescenza nullish (??) . Restituisce il suo operando sul lato destro quando il suo operando sul lato sinistro è nullo undefined, e in caso contrario restituisce il suo operando sul lato sinistro.

Si prega di verificare la compatibilità prima di utilizzarlo.


L'equivalente JavaScript dell'operatore di coalescenza null C # ( ??) utilizza un OR logico ( ||):

var whatIWant = someString || "Cookies!";

Ci sono casi (chiariti di seguito) in cui il comportamento non corrisponde a quello di C #, ma questo è il modo generale e conciso di assegnare valori predefiniti / alternativi in ​​JavaScript.


Una precisazione

Indipendentemente dal tipo di primo operando, se si esegue il cast su un valore booleano false, l'assegnazione utilizzerà il secondo operando. Fai attenzione a tutti i casi seguenti:

alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)

Questo significa:

var whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"

48
Stringhe come "false", "undefined", "null", "0", "empty", "delete" sono tutte vere poiché sono stringhe non vuote.
circa il

4
Questo deve essere chiarito. "" non è nullo ma è considerato falso. Quindi, se stai controllando un valore per null e capita che sia "" non supererà correttamente questo test.
ScottKoon,

99
Da notare che ||restituisce il primo valore "truey" o l'ultimo "falsey" (se nessuno può valutare true) e &&funziona in modo opposto: restituendo l'ultimo valore truey o il primo falsey.
Justin Johnson,

19
Cordiali saluti a chiunque si preoccupi ancora, lo 0 e la stringa vuota vengono valutati come null se si utilizza il costruttore del tipo per dichiararlo. var whatIWant = new Number(0) || 42; // is Number {[[PrimitiveValue]]: 0} var whatIWant = new String("") || "a million bucks"; // is String {length: 0, [[PrimitiveValue]]: ""}
Kevin Heidt,

5
@LuisAntonioPestana var value = myObj && myObj.property || ''tornerà indietro ''se myObj o myObj.property sono falsi.
Ates Goral,

77
function coalesce() {
    var len = arguments.length;
    for (var i=0; i<len; i++) {
        if (arguments[i] !== null && arguments[i] !== undefined) {
            return arguments[i];
        }
    }
    return null;
}

var xyz = {};
xyz.val = coalesce(null, undefined, xyz.val, 5);

// xyz.val now contains 5

questa soluzione funziona come la funzione di coesione SQL, accetta un numero qualsiasi di argomenti e restituisce null se nessuno di essi ha un valore. Si comporta come il C # ?? operatore nel senso che "", false e 0 sono considerati NOT NULL e quindi contano come valori effettivi. Se vieni da uno sfondo .net, questa sarà la soluzione di sentimento più naturale.



13
Chiedo scusa per un'aggiunta così tardiva, ma volevo solo notare per completezza che questa soluzione ha la precisazione che non ha una valutazione di corto circuito; se i tuoi argomenti sono chiamate di funzione, verranno valutati tutti indipendentemente dal fatto che il loro valore venga restituito, il che differisce dal comportamento dell'operatore logico OR, quindi vale la pena notare.
Haravikk,

63

Sì, arriverà presto. Vedi la proposta qui e lo stato di attuazione qui .

Sembra così:

x ?? y

Esempio

const response = {
  settings: {
    nullValue: null,
    height: 400,
    animationDuration: 0,
    headerText: '',
    showSplashScreen: false
  }
};

const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false

2
Ora è nella fase 3 e pianificato per la prossima versione di TypeScript! github.com/microsoft/TypeScript/issues/26578
lautaro.dragan

1
L'operatore di coalescenza nullish ( x ?? y) e l'operatore di concatenamento opzionale ( user.address?.street) sono ora entrambi Stage 4. Ecco una buona descrizione di ciò che significa: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net,

45

Se ||come sostituzione di C # ??non è abbastanza buono nel tuo caso, perché ingoia stringhe e zeri vuoti, puoi sempre scrivere la tua funzione:

 function $N(value, ifnull) {
    if (value === null || value === undefined)
      return ifnull;
    return value;
 }

 var whatIWant = $N(someString, 'Cookies!');

1
alert (null || '') avverte ancora una stringa vuota, e penso che in realtà mi piaccia quell'allerta ('' || 'blah') avvisa blah piuttosto che una stringa vuota - buono a sapersi però! (+1)
Daniel Schaffer,

1
Penso che potrei effettivamente preferire la definizione di una funzione che ritorna falsese (rigorosamente) nulla / non definita e truealtrimenti - usarla con un valore logico o; potrebbe essere più leggibile di molte chiamate di funzioni nidificate. es. $N(a) || $N(b) || $N(c) || dè più leggibile di $N($N($N(a, b), c), d).
Bob,

La soluzione di Brent Larsen è più generica
Assimilater,

if .. return .. else ... returnè il caso perfetto per un ternario. return (value === null || value === void 0) ? ifnull : value;
Alex McMillan,

15

Nessuno ha menzionato qui il potenziale per NaN, che - per me - è anche un valore nullo. Quindi, ho pensato di aggiungere i miei due centesimi.

Per il codice dato:

var a,
    b = null,
    c = parseInt('Not a number'),
    d = 0,
    e = '',
    f = 1
;

Se dovessi usare l' ||operatore, otterrai il primo valore non falso:

var result = a || b || c || d || e || f; // result === 1

Se usi il tipico metodo di coalescenza, come pubblicato qui , otterrai c, che ha il valore:NaN

var result = coalesce(a,b,c,d,e,f); // result.toString() === 'NaN'

Nessuno di questi mi sembra giusto. Nel mio piccolo mondo di logica di coesione, che può differire dal tuo mondo, considero indefiniti, null e NaN come tutti "null-ish". Quindi, mi aspetterei di tornare d(zero) dal metodo di coalescenza.

Se il cervello di qualcuno funziona come il mio e si desidera escludere NaN, questo metodo consentirà di:

function coalesce() {
    var i, undefined, arg;

    for( i=0; i < arguments.length; i++ ) {
        arg = arguments[i];
        if( arg !== null && arg !== undefined
            && (typeof arg !== 'number' || arg.toString() !== 'NaN') ) {
            return arg;
        }
    }
    return null;
}

Per coloro che desiderano che il codice sia il più breve possibile e non dispiaccia un po 'di chiarezza, è possibile utilizzare anche questo come suggerito da @impinball. Questo sfrutta il fatto che NaN non è mai uguale a NaN. Puoi saperne di più qui: Perché NaN non è uguale a NaN?

function coalesce() {
    var i, arg;

    for( i=0; i < arguments.length; i++ ) {
        arg = arguments[i];
        if( arg != null && arg === arg ) { //arg === arg is false for NaN
            return arg;
        }
    }
    return null;
}

Best practice: considera gli argomenti come simili a array, sfrutta NaN! == NaN ( typeof+ num.toString() === 'NaN'è ridondante), archivia l'argomento corrente in una variabile anziché arguments[i].
Isiah Meadows il

@impinball, la modifica suggerita non funziona, restituisce NaN invece di 0 (zero) dal mio caso di test. Potrei tecnicamente rimuovere il !== 'number'controllo poiché ho già valutato che non lo è nullo undefined, ma questo ha il vantaggio di essere molto chiaro a chiunque legga questo codice e la condizione funzionerà indipendentemente dall'ordine. I tuoi altri suggerimenti riducono leggermente il codice, quindi li userò.
Kevin Nelson,

2
@impinball, ho trovato il tuo bug nella modifica suggerita, l'hai lasciato come arg !== arg, ma hai bisogno che sia arg === arg... quindi funziona. Tuttavia, questo ha lo svantaggio di essere molto poco chiari su ciò che stai facendo ... richiede un commento nel codice per evitare di essere rimosso dalla persona successiva che passa attraverso il codice e pensa che arg === argsia ridondante ... ma lo metterò su Comunque.
Kevin Nelson,

Buona pesca. E comunque, questo è un modo veloce per controllare le NaN sfruttando il fatto NaN! == NaN. Se lo desideri, puoi spiegarlo.
Isiah Meadows il

1
verificare che "non sia un numero" può essere sostituito con una funzione integrata: isNaN ()
Yury Kozlov,

5

attenzione alla definizione specifica di JavaScript di null. ci sono due definizioni per "nessun valore" in javascript. 1. Null: quando una variabile è nulla, significa che non contiene dati al suo interno, ma la variabile è già definita nel codice. come questo:

var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts

in tal caso, il tipo di variabile è in realtà Object. Provalo.

window.alert(typeof myEmptyValue); // prints Object
  1. Non definito: quando una variabile non è stata definita prima nel codice e, come previsto, non contiene alcun valore. come questo:

    if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
    // alerts

in tal caso, il tipo di variabile è "non definito".

si noti che se si utilizza l'operatore di confronto per la conversione dei tipi (==), JavaScript agirà allo stesso modo per entrambi questi valori vuoti. per distinguerli, utilizzare sempre l'operatore di confronto di tipo rigoroso (===).


1
In realtà, null è un valore. È un valore speciale di tipo Object. Una variabile impostata su null significa che contiene dati, che sono un riferimento all'oggetto null. Una variabile può essere definita con un valore non definito nel codice. Questo non è lo stesso della variabile non dichiarata.
Ates Goral,

La differenza effettiva tra una variabile dichiarata o meno: alert (window.test) / * undefined * /; alert ("test" nella finestra) / * false * /; window.test = undefined; alert (window.test) / * * indefinito /; alert ("test" nella finestra) / * true * /; per (var p nella finestra) {/ * p può essere "test" * /}
Ates Goral

1
tuttavia (un po 'paradossale) puoi definire una variabile con il valore indefinitovar u = undefined;
Serge

@AtesGoral re null. Mentre ciò che dici è vero, per convenzione , "null" rappresenta "l'assenza di dati (utili)" . Quindi è considerato "nessun dato". E non dimentichiamo che questa è una risposta a una domanda su "un operatore a coalescenza nulla"; in questo contesto, null è sicuramente trattato come "nessun dato", indipendentemente da come viene rappresentato internamente.
ToolmakerSteve

4

Dopo aver letto i tuoi chiarimenti, la risposta di @Ates Goral ti fornisce istruzioni su come eseguire la stessa operazione che stai eseguendo in C # in JavaScript.

La risposta di @ Gumbo fornisce il modo migliore per verificare la presenza di null; tuttavia, è importante notare la differenza ==rispetto ===a JavaScript, specialmente quando si tratta di problemi di controllo di undefinede / o null.

C'è un ottimo articolo sulla differenza in due termini qui . Fondamentalmente, capisci che se usi ==invece di ===, JavaScript proverà a fondere i valori che stai confrontando e restituirà quale sia il risultato del confronto dopo questa coalescenza.


Una cosa che mi ha infastidito di quell'articolo (e Jash) è, una proprietà indefinita di window.hello che viene valutata come nulla per qualche motivo. Dovrebbe invece essere indefinito. Provalo console di errore Firefox e vedi di persona.
Ates Goral,

3

Si noti che la create-react-appcatena di strumenti di React supporta la coalescenza nulla dalla versione 3.3.0 (rilasciata il 5.12.2019) . Dalle note di rilascio:

Operatori opzionali concatenati e a coalescenza nullo

Ora supportiamo gli operatori opzionali di concatenamento e di coalizione nulli!

// Optional chaining
a?.(); // undefined if `a` is null/undefined
b?.c; // undefined if `b` is null/undefined

// Nullish coalescing
undefined ?? 'some other default'; // result: 'some other default'
null ?? 'some other default'; // result: 'some other default'
'' ?? 'some other default'; // result: ''
0 ?? 300; // result: 0
false ?? true; // result: false

Detto questo, nel caso in cui usi create-react-app3.3.0+, puoi iniziare a utilizzare l'operatore null-coalesce già oggi nelle tue app React.


3

Sì, e la sua proposta è ora Stage 4 . Ciò significa che la proposta è pronta per essere inclusa nello standard formale ECMAScript. Puoi già utilizzarlo nelle recenti versioni desktop di Chrome, Edge e Firefox, ma dovremo aspettare ancora un po 'prima che questa funzionalità raggiunga la stabilità cross-browser.

Dai un'occhiata al seguente esempio per dimostrare il suo comportamento:

// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = undefined;
const var2 = "fallback value";

const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);

L'esempio precedente equivale a:

const var1 = undefined;
const var2 = "fallback value";

const result = (var1 !== null && var1 !== undefined) ?
    var1 :
    var2;
console.log(`Nullish coalescing results in: ${result}`);

Si noti che coalescenza nullish sarà non minaccia falsy valori del modo in cui l' ||operatore ha fatto (si verifica solo i undefinedo nullvalori), da qui il seguente frammento agirà come segue:

// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = ""; // empty string
const var2 = "fallback value";

const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);


Per gli utenti di TypScript, a partire da TypeScript 3.7 , questa funzione è ora disponibile anche.


2

Speriamo che sarà presto disponibile in Javascript, poiché è in fase di proposta a partire da aprile 2020. Puoi monitorare lo stato qui per compatibilità e supporto - https://developer.mozilla.org/en-US/docs/Web/ JavaScript / Reference / Operatori / Nullish_coalescing_operator

Per le persone che usano Typescript, è possibile utilizzare l' operatore di coalescenza nullish da Typescript 3.7

Dai documenti -

Puoi pensare a questa funzione - l' ??operatore - come un modo per "ripiegare" su un valore predefinito quando hai a che fare con nullo undefined. Quando scriviamo codice come

let x = foo ?? bar();

questo è un nuovo modo di dire che il valore fooverrà usato quando è "presente"; ma quando è nullo undefined, calcola bar()al suo posto.


0

Ok una risposta adeguata

Esiste in JavaScript? Sì, lo fa. MA. È attualmente al 2020-02-06 nella fase 3 e non è ancora supportato ovunque.Segui il link nell'URL seguente e vai alle intestazioni "Specifiche" e "Compatibilità del browser" per maggiori informazioni su dove si trova.

Citazione da: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

L'operatore di coalescenza nullish (??) è un operatore logico che restituisce il suo operando sul lato destro quando il suo operando sul lato sinistro è nullo o non definito, e altrimenti restituisce il suo operando sul lato sinistro.

Contrariamente all'operatore logico OR (||), l'operando di sinistra viene restituito se si tratta di un valore errato che non è nullo o non definito. In altre parole, se usi || per fornire un valore predefinito a un'altra variabile foo, è possibile che si verifichino comportamenti imprevisti se si considerano alcuni valori falsi utilizzabili (ad es. '' o 0). Vedi sotto per altri esempi.

Vuoi esempi? Segui il link che ho pubblicato, ha tutto.



Il collegamento MDN è utile ma questa è una risposta duplicata. Dovresti invece commentare sotto la risposta di Vaughan.
Chris,

@Chris La sua risposta non è sufficiente, quindi la mia risposta.
Karl Morrison,

0

Ora ha il pieno supporto nell'ultima versione dei principali browser come Chrome, Edge, Firefox, Safari ecc. Ecco il confronto tra l'operatore null e Nullish Coalescing Operator

const response = {
        settings: {
            nullValue: null,
            height: 400,
            animationDuration: 0,
            headerText: '',
            showSplashScreen: false
        }
    };
    /* OR Operator */
    const undefinedValue = response.settings.undefinedValue || 'Default Value'; // 'Default Value'
    const nullValue = response.settings.nullValue || 'Default Value'; // 'Default Value'
    const headerText = response.settings.headerText || 'Hello, world!'; //  'Hello, world!'
    const animationDuration = response.settings.animationDuration || 300; //  300
    const showSplashScreen = response.settings.showSplashScreen || true; //  true
    /* Nullish Coalescing Operator */
    const undefinedValue = response.settings.undefinedValue ?? 'Default Value'; // 'Default Value'
    const nullValue = response.settings.nullValue ?? ''Default Value'; // 'Default Value'
    const headerText = response.settings.headerText ?? 'Hello, world!'; // ''
    const animationDuration = response.settings.animationDuration ?? 300; // 0
    const showSplashScreen = response.settings.showSplashScreen ?? true; //  false
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.