Gibt es in JavaScript einen "Null-Koaleszenz" -Operator?


1381

Gibt es in Javascript einen Null-Koaleszenz-Operator?

In C # kann ich beispielsweise Folgendes tun:

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

Die beste Annäherung, die ich für Javascript herausfinden kann, ist die Verwendung des bedingten Operators:

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

Welches ist irgendwie icky IMHO. Kann ich es besser machen


31
Anmerkung von 2018: Die x ?? ySyntax befindet sich jetzt im Status des Vorschlags der Stufe 1 - nullish coalescing
Aprillion

2
Es gibt jetzt ein Babel-Plugin, das genau diese Syntax enthält.
Jonathan Sudiaman

10
Hinweis von 2019: Jetzt ist Stufe 3 Status!
Daniel Schaffer

3
Hinweis vom Januar 2020: Der Nullish-Koaleszenzoperator ist in Firefox 72 nativ verfügbar, der optionale Verkettungsoperator jedoch noch nicht.
Kir Kanos

4
Der nullish Coalescing Operator ( x ?? y) und der optionale Chaining Operator ( user.address?.street) sind jetzt beide Stufe 4. Hier ist eine gute Beschreibung dessen, was das bedeutet: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net

Antworten:


2134

Aktualisieren

JavaScript unterstützt jetzt den nullish coalescing operator (??) . Es gibt seinen Operanden auf der rechten Seite zurück, wenn sein Operand auf der linken Seite nulloder ist undefined, und gibt ansonsten seinen Operanden auf der linken Seite zurück.

Bitte überprüfen Sie die Kompatibilität, bevor Sie es verwenden.


Das JavaScript-Äquivalent des C # -Null-Koaleszenzoperators ( ??) verwendet ein logisches ODER ( ||):

var whatIWant = someString || "Cookies!";

Es gibt Fälle (unten erläutert), in denen das Verhalten nicht mit dem von C # übereinstimmt. Dies ist jedoch die allgemeine, knappe Methode zum Zuweisen von Standard- / Alternativwerten in JavaScript.


Klärung

Unabhängig vom Typ des ersten Operanden wird bei der Umwandlung in einen Booleschen falseWert der zweite Operand verwendet. Achten Sie auf alle folgenden Fälle:

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

Das heisst:

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
Zeichenfolgen wie "false", "undefined", "null", "0", "leer", "gelöscht" sind alle wahr, da es sich um nicht leere Zeichenfolgen handelt.
einige

4
Dies muss geklärt werden. "" ist nicht null, sondern gilt als falsch. Wenn Sie also einen Wert auf null prüfen und dieser zufällig "" ist, wird dieser Test nicht korrekt bestanden.
ScottKoon

99
Bemerkenswert ist, dass ||der erste "truey" -Wert oder der letzte "falsey" -Wert zurückgegeben wird (wenn keiner als true ausgewertet werden kann) und dass dies &&umgekehrt funktioniert: Rückgabe des letzten truey-Werts oder des ersten falsey-Werts.
Justin Johnson

19
Zu Ihrer Information für alle, die sich noch darum kümmern, dass die 0 und die leere Zeichenfolge genauso wie Null ausgewertet werden, wenn Sie den Konstruktor des Typs verwenden, um sie zu deklarieren. 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 || ''wird zurückgreifen, ''wenn entweder myObj oder myObj.property falsch ist.
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

Diese Lösung funktioniert wie die SQL-Koaleszenzfunktion, akzeptiert eine beliebige Anzahl von Argumenten und gibt null zurück, wenn keines von ihnen einen Wert hat. Es verhält sich wie das C # ?? Operator in dem Sinne, dass "", false und 0 als NOT NULL betrachtet werden und daher als tatsächliche Werte gelten. Wenn Sie aus einem .net-Hintergrund stammen, ist dies die natürlichste Lösung.



13
Entschuldigung für eine so späte Hinzufügung, aber ich wollte der Vollständigkeit halber nur erwähnen, dass diese Lösung den Vorbehalt hat, dass sie keine Kurzschlussbewertung hat; Wenn Ihre Argumente Funktionsaufrufe sind, werden sie alle ausgewertet, unabhängig davon, ob ihr Wert zurückgegeben wird, was sich vom Verhalten des logischen ODER-Operators unterscheidet.
Haravikk

63

Ja, es kommt bald. Siehe Vorschlag hier und Implementierungsstatus hier .

Es sieht aus wie das:

x ?? y

Beispiel

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
Es ist jetzt in Stufe 3 und für die nächste TypeScript-Version geplant! github.com/microsoft/TypeScript/issues/26578
lautaro.dragan

1
Der nullish Coalescing Operator ( x ?? y) und der optionale Chaining Operator ( user.address?.street) sind jetzt beide Stufe 4. Hier ist eine gute Beschreibung dessen, was das bedeutet: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net

45

Wenn ||als Ersatz für C # ??in Ihrem Fall nicht gut genug ist, weil leere Zeichenfolgen und Nullen verschluckt werden, können Sie jederzeit Ihre eigene Funktion schreiben:

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

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

1
alert (null || '') warnt immer noch eine leere Zeichenfolge, und ich glaube, ich mag diese Warnung ('' || 'blah') eher als bla als als leere Zeichenfolge - gut zu wissen! (+1)
Daniel Schaffer

1
Ich denke, ich könnte es tatsächlich vorziehen, eine Funktion zu definieren, die zurückgibt, falsewenn (streng) null / undefiniert und trueanderweitig - mit einem logischen oder; Es könnte lesbarer sein als viele verschachtelte Funktionsaufrufe. zB $N(a) || $N(b) || $N(c) || dist besser lesbar als $N($N($N(a, b), c), d).
Bob

Brent Larsens Lösung ist allgemeiner
Assimilater

if .. return .. else ... returnist der perfekte Fall für einen ternären. return (value === null || value === void 0) ? ifnull : value;
Alex McMillan

15

Niemand hat hier das Potenzial für erwähnt NaN, das für mich auch ein Nullwert ist. Also dachte ich, ich würde meine zwei Cent hinzufügen.

Für den angegebenen Code:

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

Wenn Sie den ||Operator verwenden, erhalten Sie den ersten nicht falschen Wert:

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

Wenn Sie die typische coalesce Methode verwenden, wie hier aufgelistet , die Sie erhalten c, was den Wert hat:NaN

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

Beides scheint mir nicht richtig zu sein. In meiner eigenen kleinen Welt der Koaleszenzlogik, die sich von Ihrer Welt unterscheiden kann, betrachte ich undefiniert, null und NaN als alles "null-ish". Ich würde also erwarten, dvon der Koaleszenzmethode zurück zu kommen (Null).

Wenn jemandes Gehirn wie meins funktioniert und Sie es ausschließen möchten NaN, wird diese Methode Folgendes erreichen:

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;
}

Für diejenigen, die den Code so kurz wie möglich halten möchten und sich nicht um ein wenig Unklarheit kümmern möchten, können Sie diesen auch verwenden, wie von @impinball vorgeschlagen. Dies nutzt die Tatsache aus, dass NaN niemals gleich NaN ist. Mehr dazu lesen Sie hier: Warum ist NaN nicht gleich 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 Practices - Behandeln Sie Argumente als Array-ähnlich, nutzen Sie NaN! == NaN ( typeof+ num.toString() === 'NaN'ist redundant) und speichern Sie das aktuelle Argument in einer Variablen anstelle von arguments[i].
Isiah Meadows

@impinball, Ihre vorgeschlagene Bearbeitung funktioniert nicht, sie gibt NaN anstelle von 0 (Null) aus meinem Testfall zurück. Ich könnte die !== 'number'Prüfung technisch entfernen , da ich bereits ausgewertet habe, dass dies nicht der nullFall ist undefined, aber dies hat den Vorteil, dass es für jeden, der diesen Code liest, sehr klar ist und die Bedingung unabhängig von der Reihenfolge funktioniert. Ihre anderen Vorschläge verkürzen den Code geringfügig, daher werde ich diese verwenden.
Kevin Nelson

2
@impinball, ich habe deinen Fehler in deiner vorgeschlagenen Bearbeitung gefunden, du hast ihn als belassen arg !== arg, aber du musst ihn sein arg === arg... dann funktioniert er. Dies hat jedoch den Nachteil, dass es sehr unklar ist, was Sie tun ... erfordert einen Kommentar im Code, um zu verhindern, dass er von der nächsten Person entfernt wird, die den Code durchläuft und für arg === argüberflüssig hält ... aber ich werde ihn aufstellen wie auch immer.
Kevin Nelson

Guter Fang. Übrigens ist dies eine schnelle Möglichkeit, NaNs zu überprüfen und dabei die Tatsache auszunutzen, dass NaN! == NaN. Wenn Sie möchten, können Sie das erklären.
Isiah Meadows

1
Prüfung auf "keine Zahl" kann durch eine eingebaute Funktion ersetzt werden: isNaN ()
Yury Kozlov

5

Achten Sie auf die JavaScript-spezifische Definition von null. Es gibt zwei Definitionen für "kein Wert" in Javascript. 1. Null: Wenn eine Variable null ist, bedeutet dies, dass sie keine Daten enthält, die Variable jedoch bereits im Code definiert ist. so was:

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

In diesem Fall ist der Typ Ihrer Variablen tatsächlich Objekt. Probier es aus.

window.alert(typeof myEmptyValue); // prints Object
  1. Undefiniert: Wenn eine Variable zuvor nicht im Code definiert wurde und erwartungsgemäß keinen Wert enthält. so was:

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

In diesem Fall ist der Typ Ihrer Variablen "undefiniert".

Beachten Sie, dass JavaScript bei Verwendung des Vergleichsoperators für die Typkonvertierung (==) für beide Leerwerte gleichermaßen funktioniert. Verwenden Sie zur Unterscheidung immer den typenstrengen Vergleichsoperator (===).


1
Eigentlich ist null ein Wert. Es ist ein spezieller Wert vom Typ Objekt. Eine Variable, die auf null gesetzt wird, bedeutet, dass sie Daten enthält, wobei die Daten eine Referenz auf das Nullobjekt sind. Eine Variable kann mit einem in Ihrem Code undefinierten Wert definiert werden. Dies ist nicht dasselbe wie die Variable, die nicht deklariert wird.
Ates Goral

Der tatsächliche Unterschied zwischen einer deklarierten oder einer nicht deklarierten Variablen: alert (window.test) / * undefined * /; alert ("test" im Fenster) / * false * /; window.test = undefined; alert (window.test) / * undefined * /; alert ("test" im Fenster) / * true * /; für (var p im Fenster) {/ * p kann "Test" sein * /}
Ates Goral

1
aber (etwas paradoxe) können Sie definieren eine Variable mit der undefinierten Wertvar u = undefined;
Serge

@AtesGoral re null. Während das, was Sie sagen, wahr ist , steht "null" gemäß Konvention für "das Fehlen von (nützlichen) Daten" . Daher wird es als "keine Daten" angesehen. Und vergessen wir nicht, dass dies eine Antwort auf eine Frage zu "einem Null-Koaleszenz-Operator" ist. In diesem Zusammenhang wird null definitiv als "keine Daten" behandelt - unabhängig davon, wie sie intern dargestellt werden.
ToolmakerSteve

4

Nachdem Sie Ihre Erläuterungen gelesen haben, finden Sie in der Antwort von @Ates Goral die Vorgehensweise für denselben Vorgang, den Sie in C # in JavaScript ausführen.

Die Antwort von @ Gumbo bietet die beste Möglichkeit, nach Null zu suchen. jedoch ist es wichtig , den Unterschied in zu beachten , im ==Vergleich zu ===in JavaScript vor allem , wenn es um Fragen der Kontrolle für undefinedund / odernull .

Es ist ein wirklich guter Artikel über den Unterschied in beiden Begriffe hier . Verstehen Sie grundsätzlich, dass JavaScript bei Verwendung von ==anstelle von ===JavaScript versucht, die zu vergleichenden Werte zusammenzuführen und das Ergebnis des Vergleichs nach dieser Verschmelzung zurückzugeben.


Eine Sache, die mich an diesem Artikel (und Jash) gestört hat, ist, dass eine undefinierte window.hello-Eigenschaft aus irgendeinem Grund mit null bewertet wird. Es sollte stattdessen undefiniert sein. Probieren Sie die Firefox-Fehlerkonsole aus und überzeugen Sie sich selbst.
Ates Goral

3

Beachten Sie, dass die Toolkette von React create-react-appdas Null-Coalescing seit Version 3.3.0 (veröffentlicht am 5.12.2019) unterstützt . Aus den Versionshinweisen:

Optionale Verkettungs- und Nullish-Koaleszenzoperatoren

Wir unterstützen jetzt die optionalen Verkettungs- und Null-Koaleszenz-Operatoren!

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

Dieser sagte, falls Sie verwenden create-react-app3.3.0+ können Sie die Null-coalesce Betreiber bereits heute in Ihrem Reagieren Anwendungen beginnen.


3

Ja, und sein Vorschlag ist jetzt Stufe 4 . Dies bedeutet, dass der Vorschlag zur Aufnahme in den formalen ECMAScript-Standard bereit ist. Sie können es bereits in neueren Desktop-Versionen von Chrome, Edge und Firefox verwenden, aber wir müssen etwas länger warten, bis diese Funktion die browserübergreifende Stabilität erreicht.

Schauen Sie sich das folgende Beispiel an, um sein Verhalten zu demonstrieren:

// 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}`);

Das vorherige Beispiel entspricht:

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

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

Beachten Sie, dass nullish Koaleszierstruktur wird nicht Bedrohung falsy Werte die Art und Weise der ||Bediener hat (es nur prüft , ob undefinedoder nullWerte), daher der folgende Ausschnitt wirkt wie folgt:

// 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}`);


Für TypesScript-Benutzer, die mit TypeScript 3.7 beginnen , ist diese Funktion jetzt auch verfügbar.


2

Es wird hoffentlich bald in Javascript verfügbar sein, da es sich ab April 2020 in der Vorschlagsphase befindet. Sie können den Status hier auf Kompatibilität und Support überwachen - https://developer.mozilla.org/en-US/docs/Web/ JavaScript / Reference / Operators / Nullish_coalescing_operator

Für Benutzer von Typescript können Sie den nullish coalescing-Operator von verwenden Typescript Typescript 3.7 verwenden

Aus den Dokumenten -

Sie können sich diese Funktion - den ??Operator - als eine Möglichkeit vorstellen, beim Umgang mit nulloder auf einen Standardwert zurückzugreifen undefined. Wenn wir Code wie schreiben

let x = foo ?? bar();

Dies ist eine neue Art zu sagen, dass der Wert verwendet foowird, wenn er "vorhanden" ist. aber wenn es nulloder ist undefined, rechnen Sie bar()an seiner Stelle.


0

Ok eine richtige Antwort

Existiert es in JavaScript? Ja tut es. ABER. Es ist derzeit ab dem 06.02.2020 in Phase 3 und wird noch nicht überall unterstützt.Folgen Sie dem Link in der unten stehenden URL und gehen Sie zu den Überschriften "Spezifikationen" und "Browserkompatibilität", um weitere Informationen zu erhalten.

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

Der nullish coalescing operator (??) ist ein logischer Operator, der seinen Operanden auf der rechten Seite zurückgibt, wenn sein Operand auf der linken Seite null oder undefiniert ist, und ansonsten seinen Operanden auf der linken Seite zurückgibt.

Im Gegensatz zum logischen ODER-Operator (||) wird der linke Operand zurückgegeben, wenn es sich um einen falschen Wert handelt, der nicht null oder undefiniert ist. Mit anderen Worten, wenn Sie || verwenden Um einen Standardwert für eine andere Variable foo bereitzustellen, können unerwartete Verhaltensweisen auftreten, wenn Sie einige falsche Werte als verwendbar betrachten (z. B. '' oder 0). Weitere Beispiele finden Sie weiter unten.

Willst du Beispiele? Folgen Sie dem Link, den ich gepostet habe, es hat alles.



Der MDN-Link ist hilfreich, aber dies ist eine doppelte Antwort. Sie sollten stattdessen unter Vaughans Antwort einen Kommentar abgeben.
Chris

@ Chris Seine Antwort ist nicht ausreichend, daher meine Antwort.
Karl Morrison

0

Jetzt bietet es volle Unterstützung in der neuesten Version der wichtigsten Browser wie Chrome, Edge, Firefox, Safari usw. Hier ist der Vergleich zwischen dem Null-Operator und dem 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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.