Start · Sprachen · JavaScript · Referenz · Optional Chaining (?.)

Optional Chaining (?.)

Operator

Der Optional-Chaining-Operator (<code>?.</code>) greift auf Eigenschaften zu oder ruft Funktionen auf und liefert <code>undefined</code>, wenn die Referenz <code>null</code> oder <code>undefined</code> ist.

seit JavaScript ES2020 Kategorie: syntax

Signatur

obj?.prop / obj?.[expr] / func?.(args)

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

Typ
any | undefined
Beschreibung
Den Wert der Eigenschaft bzw. den Rückgabewert der Funktion, wenn alle Glieder der Kette existieren. Andernfalls 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
undefined 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

Ist 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?.().