Signatur
Beschreibung
Der Optional-Chaining-Operator (?.) greift auf eine Eigenschaft eines Objekts zu oder ruft eine Funktion auf. Ist das über diesen Operator angesprochene Objekt oder die aufgerufene Funktion undefined oder null, wird der Ausdruck kurzgeschlossen und ergibt undefined, statt einen Fehler auszulösen.
Der ?.-Operator verhält sich wie der Verkettungsoperator ., mit dem Unterschied, dass er keinen Fehler auslöst, wenn eine Referenz nullish (null oder undefined) ist, sondern den Ausdruck kurzschließt und undefined zurückgibt. Bei Funktionsaufrufen liefert er undefined, wenn die angegebene Funktion nicht existiert.
Das führt zu kürzeren und einfacheren Ausdrücken beim Zugriff auf verkettete Eigenschaften, wenn möglicherweise eine Referenz fehlt. Es ist auch hilfreich beim Erkunden des Inhalts eines Objekts, wenn nicht bekannt ist, welche Eigenschaften garantiert vorhanden sind.
Betrachten wir zum Beispiel ein Objekt obj mit einer verschachtelten Struktur. Ohne Optional Chaining erfordert der Zugriff auf eine tief verschachtelte Untereigenschaft die Validierung der dazwischenliegenden Referenzen, etwa so:
const nestedProp = obj.first && obj.first.second;
Der Wert von obj.first wird als nicht-null (und nicht-undefined) bestätigt, bevor auf den Wert von obj.first.second zugegriffen wird. Das verhindert den Fehler, der aufträte, wenn man direkt auf obj.first.second zugreifen würde, ohne obj.first zu prüfen.
Das ist ein idiomatisches Muster in JavaScript, wird aber ausschweifend, wenn die Kette lang wird, und es ist nicht sicher. Ist obj.first beispielsweise ein falsy-Wert, der nicht null oder undefined ist, wie etwa 0, würde immer noch kurzgeschlossen und nestedProp würde 0, was nicht immer erwünscht ist.
Mit dem Optional-Chaining-Operator (?.) hingegen musst du nicht mehr explizit prüfen und basierend auf dem Zustand von obj.first kurzschließen, bevor du auf obj.first.second zugreifst.
Durch die Verwendung von ?. statt nur . weiß JavaScript, implizit zu prüfen, ob obj.first nicht null oder undefined ist, bevor es versucht, auf obj.first.second zuzugreifen. Ist obj.first gleich null oder undefined, wird der Ausdruck automatisch kurzgeschlossen und liefert undefined.
Optional Chaining kann nicht auf einer nicht deklarierten Wurzelvariable verwendet werden, wohl aber mit einer Wurzelvariable, deren Wert undefined ist.
Optional Chaining bei Funktionsaufrufen
Du kannst Optional Chaining verwenden, wenn du eine Methode aufrufen möchtest, die möglicherweise nicht existiert. Das kann etwa nützlich sein, wenn du eine API verwendest, in der eine Methode nicht verfügbar sein könnte – sei es aufgrund des Alters der Implementierung oder aufgrund einer Funktion, die auf dem Gerät des Nutzers nicht verfügbar ist.
Optional Chaining bei Funktionsaufrufen führt dazu, dass der Ausdruck automatisch undefined zurückgibt, statt eine Exception zu werfen, wenn die Methode nicht gefunden wird.
Existiert allerdings eine Eigenschaft mit diesem Namen, die keine Funktion ist, wirft ?. weiterhin eine TypeError-Exception „someInterface.customMethod is not a function".
eval?.() ist der kürzeste Weg, in den indirect eval-Modus zu gelangen.
Optional Chaining mit Ausdrücken
Du kannst den Optional-Chaining-Operator auch mit Bracket-Notation verwenden, was es erlaubt, einen Ausdruck als Eigenschaftsname zu übergeben.
Das ist besonders nützlich für Arrays, da Array-Indizes mit eckigen Klammern angesprochen werden müssen.
Ungültiges Optional Chaining
Es ist ungültig zu versuchen, dem Ergebnis eines Optional-Chaining-Ausdrucks etwas zuzuweisen.
Tags von Template Literals dürfen keine Optional Chain sein.
Der Konstruktor von new-Ausdrücken darf keine Optional Chain sein.
Kurzschließen (Short-circuiting)
Wenn Optional Chaining mit Ausdrücken verwendet wird und der linke Operand null oder undefined ist, wird der Ausdruck nicht ausgewertet. Auch nachfolgende Eigenschaftszugriffe werden nicht ausgewertet.
Dieses Kurzschluss-Verhalten tritt jedoch nur entlang einer durchgehenden „Kette" von Eigenschaftszugriffen auf. Wenn du einen Teil der Kette gruppierst, werden nachfolgende Eigenschaftszugriffe dennoch ausgewertet.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $object Pflicht | any | — | Das Objekt (oder ein Ausdruck), dessen Eigenschaft oder Methode aufgerufen werden soll. Ist dieser Wert null oder undefined, gibt der gesamte Ausdruck undefined zurück. |
| $property / expr / args Pflicht | string | symbol | any | — | Je nach Schreibweise: ein statischer Eigenschaftsname (?.prop), ein berechneter Schlüssel (?.[expr]) oder Argumente für einen optionalen Funktionsaufruf (?.(args)). |
Rückgabewert
undefined, sobald ein Glied null oder undefined ist.Beispiele
Grundlegendes Beispiel
const myMap = new Map();
myMap.set("JS", { name: "Josh", desc: "I maintain things" });
const nameBar = myMap.get("CSS")?.name;
Umgang mit optionalen Callbacks oder Event-Handlern (ohne Optional Chaining)
// Code written without optional chaining
function doSomething(onContent, onError) {
try {
// Do something with the data
} catch (err) {
// Testing if onError really exists
if (onError) {
onError(err.message);
}
}
}
Umgang mit optionalen Callbacks oder Event-Handlern (mit Optional Chaining)
// Using optional chaining with function calls
function doSomething(onContent, onError) {
try {
// Do something with the data
} catch (err) {
onError?.(err.message); // No exception if onError is undefined
}
}
Stapeln des Optional-Chaining-Operators
const customer = {
name: "Carl",
details: {
age: 82,
location: "Paradise Falls", // Detailed address is unknown
},
};
const customerCity = customer.details?.address?.city;
// This also works with optional chaining function call
const customerName = customer.name?.getName?.(); // Method does not exist, customerName is undefined
Kombination mit dem Nullish-Coalescing-Operator
function printCustomerCity(customer) {
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity);
}
printCustomerCity({
name: "Nathan",
city: "Paris",
}); // "Paris"
printCustomerCity({
name: "Carl",
details: { age: 82 },
}); // "Unknown city"
Interaktives Beispiel
const adventurer = {
name: "Alice",
cat: {
name: "Dinah",
},
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// Expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// Expected output: undefined
Ungültige Nutzung auf nicht deklarierter Variable
undeclaredVar?.prop; // ReferenceError: undeclaredVar is not defined
Kurzschließen verhindert Auswertung
const potentiallyNullObj = null;
let x = 0;
const prop = potentiallyNullObj?.[x++];
console.log(x); // 0 as x was not incremented
Gruppierung unterbricht Kurzschließen
const potentiallyNullObj = null;
const prop = (potentiallyNullObj?.a).b;
// TypeError: Cannot read properties of undefined (reading 'b')
// Wichtig · Fallstricke
someInterface selbst null oder undefined, wird weiterhin eine TypeError-Exception ausgelöst („someInterface is null"). Wenn du erwartest, dass someInterface selbst null oder undefined sein kann, musst du ?. auch an dieser Stelle verwenden: someInterface?.customMethod?.().