Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional chaining '?.' #90

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 74 additions & 64 deletions 1-js/04-object-basics/07-optional-chaining/article.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,65 @@

# Optional chaining '?.'
# Optionale Verkettung '?.'

[recent browser="new"]

The optional chaining `?.` is an error-proof way to access nested object properties, even if an intermediate property doesn't exist.
Der Optionale-Verkettungs-Operator `?.` ermöglicht es, auf einen Wert einer verschachtelten
Objekteigenschaft zuzugreifen, ohne dass jede Eigenschaft existieren muss.
Comment on lines +6 to +7

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


## The problem
## Das Problem

If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common.
Personen, die erst gerade dabei sind, JavaScript zu lernen, kamen wahrscheinlich mit diesem
Problem noch nicht in Berührung, allerdings tritt dieses sehr häufig in der Praxis auf.
Comment on lines +11 to +12

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


For example, some of our users have addresses, but few did not provide them. Then we can't safely read `user.address.street`:
Beispielsweise haben einige unserer Benutzer eine Adresse, allerdings fehlt diese bei manchen.
Dadurch ist die Verwendung von `user.address.street` nicht sicher:
Comment on lines +14 to +15

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


```js run
let user = {}; // the user happens to be without address
let user = {}; // Benutzer ohne Adresse

alert(user.address.street); // Error!
alert(user.address.street); // Fehler!
```

Or, in the web development, we'd like to get an information about an element on the page, but it may not exist:
Oder man möchte in der Webentwicklung auf ein bestimmtes Element auf der Webseite zugreifen,
das aber möglicherweise gar nicht existiert:
Comment on lines +23 to +24

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


```js run
// Error if the result of querySelector(...) is null
// Fehler, wenn das Ergebnis von querySelector(...) null ist
let html = document.querySelector('.my-element').innerHTML;
```

Before `?.` appeared in the language, the `&&` operator was used to work around that.
Vor der Einführung von `?.` in die Sprache wurde oft der `&&` Operator verwendet, um das
Problem zu umgehen.
Comment on lines +31 to +32

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


For example:
Zum Beispiel:

```js run
let user = {}; // user has no address
let user = {}; // Benutzer hat keine Adresse

alert( user && user.address && user.address.street ); // undefined (no error)
alert( user && user.address && user.address.street ); // undefined (kein Fehler)
```

AND'ing the whole path to the property ensures that all components exist, but is cumbersome to write.
Den gesamten Pfad und die Eigenschaft mit UND zu verknüpfen stellt sicher, dass alle Komponenten
existieren. Allerdings ist dies sehr umständlich.
Comment on lines +42 to +43

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


## Optional chaining
## Optionale Verkettung

The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`.
Der Optionale-Verkettungs-Operator (Optional Chaining) `?.` stoppt die Auswertung und gibt
`undefined` zurück, sobald der Teil vor `?.` zu `undefined` oder `null` evaluiert.
Comment on lines +47 to +48

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.**
**Aus Platzgründen verwenden wir im weiteren Verlauf dieses Artikels den Begriff
"etwas existiert", wenn etwas nicht `null` oder `undefined` ist.**
Comment on lines +50 to +51

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


Here's the safe way to access `user.address.street`:
Hier die sichere Variante um auf `user.address.street` zuzugreifen:

```js run
let user = {}; // user has no address
let user = {}; // Benutzer hat keine Adresse

alert( user?.address?.street ); // undefined (no error)
alert( user?.address?.street ); // undefined (kein Fehler)
```

Reading the address with `user?.address` works even if `user` object doesn't exist:
Es ist sogar möglich, die Adresse von `user?.address` zu lesen, obwohl das Objekt `user`
gar nicht existiert:
Comment on lines +61 to +62

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


```js run
let user = null;
Expand All @@ -59,117 +68,118 @@ alert( user?.address ); // undefined
alert( user?.address.street ); // undefined
```

Please note: the `?.` syntax makes optional the value before it, but not any further.
Hinweis: Die Syntax mit `?.` macht nur den Wert davor optional, nicht den Wert der danach kommt.

In the example above, `user?.` allows only `user` to be `null/undefined`.
Im oberen Beispiel `user?.` darf also nur `user` den Wert `null/undefined` haben.

On the other hand, if `user` does exist, then it must have `user.address` property, otherwise `user?.address.street` gives an error at the second dot.
Wenn `user` allerdings existiert, so muss das Objekt die Eigenschaft `user.address` besitzen,
sonst liefert `user?.address.street` beim zweiten Punkt einen Fehler.
Comment on lines +75 to +76

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 Zeilen


```warn header="Don't overuse the optional chaining"
We should use `?.` only where it's ok that something doesn't exist.
```warn header="Optional Chaining nicht übertreiben"
Der Operator `?.` sollte nur verwendet werden, wenn es erlaubt ist, dass etwas nicht existiert.

For example, if according to our coding logic `user` object must be there, but `address` is optional, then `user.address?.street` would be better.
Wenn zum Beispiel laut unserer Geschäftslogik das Objekt `user` existieren muss, aber `address` ist optional, dann wäre es besser `user.address?.street` zu verwenden.

So, if `user` happens to be undefined due to a mistake, we'll know about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug.
Wenn dann `user` fälschlicherweise nicht definiert ist, merken wir es und können den Fehler beheben. Sonst passieren Programmierfehler im Hintergrund und können nur schwer behoben werden.
```

````warn header="The variable before `?.` must be declared"
If there's no variable `user` at all, then `user?.anything` triggers an error:
````warn header="Die Variable vor `?.` muss deklariert sein"
Existiert die Variable `user` nicht, so liefert `user?.anything` einen Fehler:

```js run
// ReferenceError: user is not defined
user?.address;
```
There must be `let/const/var user`. The optional chaining works only for declared variables.
Es muss ein `let/const/var user` irgendwo geben. Die optionale Verkettung funktioniert nur bei deklarierten Variablen.
````

## Short-circuiting
## Kurzschlussverfahren

As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist.
Wie schon erwähnt stoppt der Operator `?.` die Ausführung sobald der linke Teil nicht existiert.

So, if there are any further function calls or side effects, they don't occur:
Mögliche Funktionsaufrufe oder Nebeneffekte werden also nicht ausgeführt:

```js run
let user = null;
let x = 0;

user?.sayHi(x++); // nothing happens
user?.sayHi(x++); // nichts passiert

alert(x); // 0, value not incremented
alert(x); // 0, Wert hat sich nicht erhöht
```

## Other cases: ?.(), ?.[]
## Weitere Formen: ?.(), ?.[]

The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets.
Der Optionale-Verkettungs-Operatorr `?.` ist in Wahrheit gar kein Operator sondern ein besonderes Syntax-Konstrukt, das auch mit Funktionen und eckigen Klammern funktioniert.

For example, `?.()` is used to call a function that may not exist.
Beispielsweise lässt sich `?.()` zum Aufruf einer Funktion nutzen die es möglicherweise nicht gibt.

In the code below, some of our users have `admin` method, and some don't:
Im folgenden Codeausschnitt haben manche Benutzer die Methode `admin` und manche nicht:

```js run
let user1 = {
admin() {
alert("I am admin");
alert("Ich bin Administrator");
}
}

let user2 = {};

*!*
user1.admin?.(); // I am admin
user1.admin?.(); // Ich bin Administrator
user2.admin?.();
*/!*
```

Here, in both lines we first use the dot `.` to get `admin` property, because the user object must exist, so it's safe read from it.
In beiden Zeilen verwenden wir zuerst die Punktnotation `.` um die Eigenschaft `admin` abzurufen. Da es das Objekt `user` geben muss, ist es sicher darauf zuzugreifen.

Then `?.()` checks the left part: if the admin function exists, then it runs (for `user1`). Otherwise (for `user2`) the evaluation stops without errors.
Dann prüft `?.()` die linke Seite: wenn die admin Funktion existiert, dann wird diese ausgeführt (für `user1`). Sonst (für `user2`) stoppt die Ausführung ohne Fehler.

The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist.
Die Syntax `?.[]` funktioniert auch, wenn man mit eckigen Klammern anstatt mit der Punktnotation auf eine Objekteigenschaft zugreifen möchte. Ähnlich wie vorher ist es möglich, eine Eigenschaft auf sichere Art und Weise zu lesen, die es vielleicht nicht gibt.

```js run
let user1 = {
firstName: "John"
firstName: "Johannes"
};

let user2 = null; // Imagine, we couldn't authorize the user
let user2 = null; // Benutzer konnte möglicherweise nicht authorisiert werden

let key = "firstName";

alert( user1?.[key] ); // John
alert( user1?.[key] ); // Johannes
alert( user2?.[key] ); // undefined

alert( user1?.[key]?.something?.not?.existing); // undefined
```

Also we can use `?.` with `delete`:
Wir können `?.` auch mit `delete` verwenden:

```js run
delete user?.name; // delete user.name if user exists
delete user?.name; // lösche user.name wenn der Benutzer existiert
```

```warn header="We can use `?.` for safe reading and deleting, but not writing"
The optional chaining `?.` has no use at the left side of an assignment:
```warn header="Wir können `?.` für sicheres Lesen und Löschen verwenden, aber nicht bei Zuweisungen"
Der Optionale-Verkettungs-Operator `?.` findet keine Anwendung auf der linken Seite eines Statements:

```js run
// the idea of the code below is to write user.name, if user exists
// der Name soll an user.name zugewiesen werden, wenn der Benutzer existiert

user?.name = "John"; // Error, doesn't work
// because it evaluates to undefined = "John"
user?.name = "Johannes"; // Fehler, funktioniert nicht
// weil es zu undefined = "Johannes" evaluiert wird
```

## Summary
## Zusammenfassung

The `?.` syntax has three forms:
Die `?.` Syntax hat drei Formen:

1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`.
2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`.
3. `obj?.method()` -- calls `obj.method()` if `obj` exists, otherwise returns `undefined`.
1. `obj?.prop` -- liefert `obj.prop` wenn `obj` existiert, sonst `undefined`.
2. `obj?.[prop]` -- liefert `obj[prop]` wenn `obj` existiert, sonst `undefined`.
3. `obj?.method()` -- ruft `obj.method()` auf wenn `obj` existiert, sonst wird `undefined` zurückgegeben.

As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so.
Wie wir sehen können sind alle drei Formen unkompliziert und leicht zu verwenden. Das `?.` prüft die linke Seite auf `null/undefined` und erlaubt die weitere Ausführung wenn dies nicht der Fall ist.

A chain of `?.` allows to safely access nested properties.
Eine Verkettung von `?.` erlaubt den sicheren Zugriff auf verschachtelte Objekteigenschaften.

Still, we should apply `?.` carefully, only where it's ok that the left part doesn't to exist.
Trotzdem sollten wir `?.` mit Vorsicht genießen und nur dann benutzen, wenn es beabsichtigt ist, dass der linke Teil nicht existiert.

So that it won't hide programming errors from us, if they occur.
Dann werden mögliche Programmierfehler auch angezeigt, wenn diese auftreten.