
DerNullish coalescing operator ist ein neuer und zusätzlicher JavaScript-Operator, der seit Juni 2020 mit ECMAScript 2020 (ES2020) der Programmiersprache zur Verfügung steht.
Er ist neben den (vielleicht) bekanntenbinären logischen Operatoren (Binary Logical Operators)&&
(UND) und||
(ODER) der drittenicht binäre Operator und hat die Schreibweise??
.
Zum Einsatz kommt er immer dann, wenn ich explizit prüfen möchte ob der Wert einer Variable vorliegt um diesen zu nutzen oder, wenn der Wert nicht vorliegt, mit einem anderen Wert weiter zu arbeiten.
Hier für mich der "Klassiker": Einmal mit einemif
-Block, dann in einer "vereinfachten" Schreibweise mit demODER-Operator und zu guter letzt in der Schreibweise mit dem neuenNullish coalescing operator.
// Long versionletsecondValue="DEFAULT_VALUE";if(firstValue!==null&&firstValue!==undefined&&firstValue!==""){secondValue=firstValue;}// Shorthand with OR-OperatorsecondValue=firstValue||"DEFAULT_VALUE";// With Nullish-OperatorsecondValue=firstValue??"DEFAULT_VALUE";
Die erste Vereinfachung, mit demODER-Operator, funktioniert in den meisten Fällen, deckt jedochnicht den Fall ab mit bool‘schen Werten zu arbeiten.
Doch gehen wir es Schritt für Schritt durch und schauen erstmal warum die Varianten mit demODER-Operator funktioniert um dann auf den meist "besseren"Nullish coalescing operator auszuweichen.
ODER-Operator
Der binäre logische Operator (Binary Logical Operator)||
(ODER) ist wie folgt definiert:
{Ausdruck linke Seite}|| {Ausdruck rechte Seite}
D.h. liefert der Ausdruck auf der linken Seite den Wertfalse
wird der Ausdruck auf der rechten Seite interpretiert, ansonsten wird der Ausdruck der linken Seite interpretiert.
Für unsere "Vereinfachung" von oben…
letsecondValue=firstValue||"DEFAULT_VALUE";
bedeutet es, dass wenn die VariablefirstValue
den Werttrue
liefert, wird dieser Wert zurückgegeben (und in diesem Fall der VariablensecondValue
zugewiesen). Liefert die VariablefirstValue
allerdingsfalse
wird der Wert der rechten Seite der VariablesecondValue
zugewiesen - in meinem Fall also der WertDEFAULT_VALUE
.
Schritt für Schritt
Gehen wir mein obiges Beispiel Schritt für Schritt durch und schauen was ich meine mit…
Die erste Vereinfachung, mit demODER-Operator, funktioniert in den meisten Fällen, deckt jedochnicht den Fall ab mit bool‘schen Werten zu arbeiten.
und wie uns derNullish coalescing operator hier hilft.
Dazu packe ich mein Beispiel in eine Funktion und führe diese anschließend aus:
functiondoSomethingAmazing(firstValue){letsecondValue="DEFAULT_VALUE";if(firstValue!==null&&firstValue!==undefined&&firstValue!==""){// Do somthing greatesecondValue=firstValue;}returnsecondValue;}doSomethingAmazing(1);// 1 ✅doSomethingAmazing(42);// 42 ✅doSomethingAmazing(null);// DEFAULT_VALUE ✅doSomethingAmazing("");// DEFAULT_VALUE ✅doSomethingAmazing(/* No value means `undefined` as value */);// DEFAULT_VALUE ✅doSomethingAmazing(true);// true ✅doSomethingAmazing(false);// false ✅
🥳 Alles wunderbar und der Code funktioniert auch mit bool'schen Werten. 🥳
Reflexartig setzt bei mir das Gefühl ein diesen Code zu "vereinfachen" und die Möglichkeiten von JavaScript für mich zu nutzen. Denn dass ein Wert vorhanden ist kann ich mit einemif (firstValue)
ermitteln, was zu dieser Version meines Codes führt:
functiondoSomethingAmazing(firstValue){letsecondValue="DEFAULT_VALUE";if(firstValue){secondValue=firstValue;}returnsecondValue;}doSomethingAmazing(1);// 1 ✅doSomethingAmazing(42);// 42 ✅doSomethingAmazing(null);// DEFAULT_VALUE ✅doSomethingAmazing("");// DEFAULT_VALUE ✅doSomethingAmazing(/* No value means `undefined` as value */);// DEFAULT_VALUE ✅doSomethingAmazing(true);// true ✅doSomethingAmazing(false);// DEFAULT_VALUE ❌ 😮
😮 Upps…Wenn ich einfalse
an die Funktion übergebe erhalte ich den WertDEFAULT_VALUE
zurück und nicht wie erwartet den Wertfalse
🤔
Ich gehe noch einen Schritt weiter und "vereinfachen" meinen Code noch einmal; und dieses mal nutze ich denODER-Operator:
functiondoSomethingAmazing(firstValue){// Executes the right operand ("DEFAULT_VALUE")// only if the left operand (firstValue) is falsy// Dieser Einzeiler wird auch short-circuiting operator genannt 😃letsecondValue=firstValue||"DEFAULT_VALUE";returnsecondValue;}doSomethingAmazing(1);// 1 ✅doSomethingAmazing(42);// 42 ✅doSomethingAmazing(null);// DEFAULT_VALUE ✅doSomethingAmazing("");// DEFAULT_VALUE ✅doSomethingAmazing(/* No value means `undefined` as value */);// DEFAULT_VALUE ✅doSomethingAmazing(true);// true ✅doSomethingAmazing(false);// DEFAULT_VALUE ❌ 😮
Die letzte "Vereinfachung" meines Codes finde ich noch besser. Diese nimmt mir denif
-Block und macht den Code einfacher zu lesen und übersichtlicher.
Doch beide "Vereinfachung" führen zu dem selben unerwarteten Ergebnis, wenn ich die Funktion mit dem Wertfalse
aufrufe.
Was habe ich kaputt gemacht? 🤔
Ich habe nichts wirklichkaputt gemacht. Ich habe lediglich, in beiden Vereinfachungen, Funktionalität von JavaScript genutzt die davon ausgeht dass ein Wert falsch (false
) sein muss - alsofalsy ist. Im konkret Fall, mit meinemif
-Block und demODER-Operator, prüfe ich ob der WertfirstValue
falsch ist um dann den WertDEFAULT_VALUE
zu nutzen.
Wann ist ein Wert "falsy"
In JavaScript ist ein Wert genau dann falsch (false
) oderfalsy wenn diesernull
,undefined
,0
oderfalse
ist.
Und da dieses in JavaScript nunmal so ist, habe ich mit meiner "Vereinfachung" des Codes auch gleich dasVerhalten meiner Implementierung verändert 🤷
Rufe doch die letzten beiden Codebeispiele mal mit0
(Zero) auf:
doSomethingAmazing(0);
Auch hier möchte ich dass mir der Wert0
(Zero) zurückgegeben wird, doch ich erhalte - logischerweise - den WertDEFAULT_VALUE
🤷
Doch kommen wir zurück zur eigentlich Implementierung mit folgendem Ausdruck imif
-Block:
firstValue!==null&&firstValue!==undefined&&firstValue!=="")
Daraus leitet sich meine Anforderung ab dass ich prüfen möchte ob ein Wertnullish ist undnicht ob ein Wertfalsy ist, wie ich es durch meine "Vereinfachungen" (unwissentlich) gemacht habe.
Was heisstnullish
Mitnullish ist gemeint dass ein Ausdruck die Wertenull
oderundefined
haben muss, nur dann ist ernullish.
Und genau dieses ist und war es, was ich mit meiner ersten Implementierung haben wollte und umgesetzt habe.
Kann ich jetzt meine einleitendes Beipiels nicht "vereinfachen"? Muss ich, von Hand, allenullish-Werte in JavaScript selber abfragen?
😱😱😱N E I N 😱😱😱
Der Neue - Nullish coalescing operator (??
)
Hier kommtder Neue ins Spiel - der dritten logische Operatoren in JavaScript.
Meine Damen und Herren derNullish coalescing operator 🚀🚀🚀, der in JavaScript als??
geschrieben wird und wie folgt definiert ist:
{Ausdruck linke Seite}?? {Ausdruck rechte Seite}
Dieser Operator verhält sich ähnlich wie derODER-Operator, doch mit dem entscheidenden Unterschied…
Es wird geprüft ob der Ausdruck auf der linken Seite"nullish" ist.
Und nicht wie beimODER-Operator, ob der Ausdruckfalse
ist.
Ein paarBeispiele zumNullish coalescing operator:
1??"DEFAULT VALUE";// Result is: 1 ✅42??"DEFAULT VALUE";// Result is: 42 ✅null??"DEFAULT VALUE";// Result is: DEFAULT VALUE ✅undefined??"DEFAULT VALUE";// Result is: DEFAULT VALUE ✅true??"DEFAULT VALUE";// Result is: true ✅false??"DEFAULT VALUE";// Result is: false ✅0??"DEFAULT VALUE";// Result is: 0 ✅""??"DEFAULT VALUE";// Result is: "" ❓
Und mit diesem Wissen kann ich mein Codebeispiel auch wieder "vereinfachen" - und zwar so…
functiondoSomethingAmazing(firstValue){// Executes the right operand ("DEFAULT_VALUE")// only if the left operand (firstValue) is nullishletsecondValue=firstValue??"DEFAULT_VALUE";returnsecondValue;}doSomethingAmazing(1);// 1 ✅doSomethingAmazing(42);// 42 ✅doSomethingAmazing(null);// DEFAULT_VALUE ✅doSomethingAmazing(/* No value means `undefined` as value */);// DEFAULT_VALUE ✅doSomethingAmazing(true);// true ✅doSomethingAmazing(false);// false ✅doSomethingAmazing("");// "" ❓
Einen habe ich noch…
Bei meinen Beispielen mit demNullish coalescing operator wird Euch aufgefallen sein, dass der Aufruf meiner "vereinfachten" Funktionen mit einem leeren String (""
) nicht dazu führt das mirDEFAULT_VALUE
zurückgegeben wird.
Das ist für die Funktionsweise meines Beispiels nicht relevant, doch ich möchte Euch nicht verschweigen warum es dazu kommt.
Die Antwort liegt eigentlich klar vor uns: DerNullish coalescing operator (??
) prüft ob ein Wertnullish ist, alsonull
oderundefined
ist. Und ein leerer String (""
) ist in JavaScript ein leerer String und damit wedernull
nochundefined
- aberfalsy 🤣
Ein weiteres Beispiel
Gehen wir noch einen Schritt weiter und wollen dieses mal tatsächlich mit bool‘schen Werten wietrue
undfalse
arbeiten. Sagen wir, im Rahmen einer Konfiguration die genau dann einen Lebenszeichen von sich geben soll wenn wir online sind und voraussetzt dass wir (immer) online sind (per default):
functiondoSomethingAmazingWithAConfiguration({online}){// We use the OR operatorletsendKeepAlive=online||true;returnsendKeepAlive;}// We say explicit that we're onlinedoSomethingAmazingWithAConfiguration({online:true});// true ✅// We use the default-statedoSomethingAmazingWithAConfiguration({});// true ✅// We say explicit that we're offline ⚠️doSomethingAmazingWithAConfiguration({online:false});// true ❌ 😮
An dieser Stelle des Textes habe ich jetzt mit dem "falschen" Rückgabewert des letzten Aufrufes der Funktion gerechnet, doch es ist nicht das was ich wollte.
Ich möchte das der Rückgabewert der Funktion mirfalse
liefert, wenn wir offline sind, also wenn wir im übergebenem Objekt den keyonline
auffalse
setzen ({ online: false }
).
Das bekannte Problem
Mit dem gelernten macht dieses falsche Ergebnis meines Funktionsaufrufes Sinn. Dennonline || true
hat mit dem letzten Aufruf folgende Werte:false || true
.
Und wenn die linke Seite desODER-Operatorsfalse
liefert wird der Wert des Ausdrucks auf der rechten Seite genutzt (der Wert der linken Seite istfalsy) - in unserem Falltrue
🤷.
Der Code funktioniert genau wie geschrieben, doch nicht wie erwartet.
Mögliche Lösungen
Für meine Funktion, die ein Konfigurationsobjekt erwartet, könnte ich mitDestructuring arbeiten und einen Defaultwert definieren:
functiondoSomethingAmazingWithAConfiguration({online}={online:false}){returnonline;}
Oder ich nutze, statt eines Konfigurationsobjekts, einboolean
und prüfe diese mit demstrict inequality operator (!==
):
functiondoSomethingAmazingWithAConfiguration({online}){letsendKeepAlive=online!==false;returnsendKeepAlive;}
Doch in diesem Artikel ist derNullish coalescing operator der Star 🤩 und für meine Konfigurationsfunktion auch eine Lösung:
functiondoSomethingAmazingWithAConfiguration({online}){// We use the Nullish coalescing operatorletsendKeepAlive=online??true;returnsendKeepAlive;}// We say explicit that we're onlinedoSomethingAmazingWithAConfiguration({online:true});// true ✅// We use the default-statedoSomethingAmazingWithAConfiguration({});// true ✅// We say explicit that we're offlinedoSomethingAmazingWithAConfiguration({online:false});// false ✅
Anmerkung
Diesen Artikel habe ich bewusst in meiner Muttersprache (Deutsch) verfasst, da es eine sehr aktive deutsche JavaScript-Community (u.a.hier) gibt von der ich ein Teil bin und der ich hiermit etwas zurück geben möchte 🙇♂️
Oder um es mit mit dem Hashtag meines Trainer-BuddiesWebDave zu sagen:#CommunityRocks und in diesem Fall#GermanJavaScriptCommunityRocksToo 😉🚀😎
If you want to read this article in English, you are in the right placehere
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse