-
-
Notifications
You must be signed in to change notification settings - Fork 35
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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. | ||
|
||
## 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 Zeilen |
||
|
||
```js run | ||
let user = null; | ||
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 Zeilen