Skip to content
Merged
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
167 changes: 83 additions & 84 deletions 1-js/04-object-basics/07-optional-chaining/article.md
Original file line number Diff line number Diff line change
@@ -1,112 +1,112 @@

# Optional chaining '?.'
# Valgfri sammenkædning '?.'

[recent browser="new"]

The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist.
Den valgfrie sammenkædning `?.` er en sikker måde at få adgang til indlejrede objekt-egenskaber på, selvom en mellemliggende egenskab ikke eksisterer.

## The "non-existing property" problem
## Problemet med "ikke-eksisterende egenskaber"

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.
Hvis du lige er begyndt at læse vejledningen og lære JavaScript, har problemet måske ikke ramt dig endnu, men det er ret almindeligt.

As an example, let's say we have `user` objects that hold the information about our users.
Som et eksempel, lad os sige, at vi har `user`-objekter, der indeholder oplysninger om vores brugere.

Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them.
De fleste af vores brugere har adresser i `user.address`-egenskaben, med gaden `user.address.street`, men nogle har ikke angivet dem.

In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error:
I så fald, når vi forsøger at få `user.address.street`, og brugeren tilfældigvis ikke har en adresse, får vi en fejl:

```js run
let user = {}; // a user without "address" property
let user = {}; // en bruger uden "address"-egenskab

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

That's the expected result. JavaScript works like this. As `user.address` is `undefined`, an attempt to get `user.address.street` fails with an error.
Det er det forventede resultat. JavaScript fungerer sådan. Da `user.address` er `undefined`, mislykkes et forsøg på at få `user.address.street` med en fejl.

In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street").
I mange praktiske tilfælde foretrækker vi at få `undefined` i stedet for en fejl her (betydende "ingen gade").

...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element.
...og et andet eksempel. I webudvikling kan vi få et objekt, der svarer til et websideelement ved hjælp af et specielt metodekald, såsom `document.querySelector('.elem')`, og det returnerer `null`, når der ikke er et sådant element.

```js run
// document.querySelector('.elem') is null if there's no element
let html = document.querySelector('.elem').innerHTML; // error if it's null
// document.querySelector('.elem') er null, hvis der ikke er et element
let html = document.querySelector('.elem').innerHTML; // fejl, hvis det er null
```

Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` property of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result.
Hvis elementet ikke findes, får vi en fejl, når vi forsøger at få adgang til `.innerHTML`-egenskaben af `null`. Og i nogle tilfælde, når fraværet af elementet er normalt, vil vi gerne undgå fejlen og blot acceptere `html = null` som resultatet.

How can we do this?
Hvordan kan vi gøre dette?

The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this:
Den oplagte løsning ville være at tjekke værdien ved hjælp af `if` eller den betingede operator `?`, før vi får adgang til dens egenskab, sådan her:

```js
let user = {};

alert(user.address ? user.address.street : undefined);
```

It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code.
Det virker, der er ingen fejl... Men det er ret upraktisk. Som du kan se, optræder `"user.address"` to gange i koden.

Here's how the same would look for `document.querySelector`:
Her er hvordan det samme ville se ud for `document.querySelector`:

```js run
let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null;
```

We can see that the element search `document.querySelector('.elem')` is actually called twice here. Not good.
Vi kan se, at element-søgningen `document.querySelector('.elem')` faktisk kaldes to gange her. Ikke godt.

For more deeply nested properties, it becomes even uglier, as more repetitions are required.
For mere dybt indlejrede egenskaber bliver det endnu grimmere, da flere gentagelser er nødvendige.

E.g. let's get `user.address.street.name` in a similar fashion.
F.eks. lad os få `user.address.street.name` på en lignende måde.

```js
let user = {}; // user has no address
let user = {}; // user har ingen adresse

alert(user.address ? user.address.street ? user.address.street.name : null : null);
```

That's just awful, one may even have problems understanding such code.
Det er skrækkeligt!. Flere kan endda have problemer med bare at forstå sådan kode.

There's a little better way to write it, using the `&&` operator:
Der er en lidt bedre måde at skrive det på ved hjælp af `&&`-operatoren:

```js run
let user = {}; // user has no address
let user = {}; // user har ingen adresse

alert( user.address && user.address.street && user.address.street.name ); // undefined (no error)
alert( user.address && user.address.street && user.address.street.name ); // undefined (ingen fejl)
```

AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal.
At "AND'e" hele stien til egenskaben sikrer, at alle komponenter eksisterer (hvis ikke, stopper evalueringen), men det er heller ikke ideelt.

As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times.
Som du kan se, optræder egenskabsnavne stadig flere gange i koden. F.eks. i koden ovenfor optræder `user.address` tre gange.

That's why the optional chaining `?.` was added to the language. To solve this problem once and for all!
Derfor blev den valgfrie kædning `?.` tilføjet til sproget. For at løse dette problem én gang for alle!

## Optional chaining
## Valgfri kædning

The optional chaining `?.` stops the evaluation if the value before `?.` is `undefined` or `null` and returns `undefined`.
Den valgfrie kædning `?.` stopper evalueringen, hvis værdien før `?.` er `undefined` eller `null` og returnerer `undefined`.

**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.**
**Fremover i denne artikel, for korthedens skyld, vil vi sige, at noget "eksisterer", hvis det ikke er `null` og ikke `undefined`.**

In other words, `value?.prop`:
- works as `value.prop`, if `value` exists,
- otherwise (when `value` is `undefined/null`) it returns `undefined`.
Med andre ord, `value?.prop`:
- fungerer som `value.prop`, hvis `value` eksisterer,
- ellers (når `value` er `undefined/null`) returnerer det `undefined`.

Here's the safe way to access `user.address.street` using `?.`:
Her er den sikre måde at få adgang til `user.address.street` ved hjælp af `?.`:

```js run
let user = {}; // user has no address
let user = {}; // user har ingen adresse

alert( user?.address?.street ); // undefined (no error)
alert( user?.address?.street ); // undefined (ingen fejl)
```

The code is short and clean, there's no duplication at all.
Koden er kort og ren, der er ingen duplikation overhovedet.

Here's an example with `document.querySelector`:
Her er et eksempel med `document.querySelector`:

```js run
let html = document.querySelector('.elem')?.innerHTML; // will be undefined, if there's no element
let html = document.querySelector('.elem')?.innerHTML; // vil være undefined, hvis der ikke er noget element
```

Reading the address with `user?.address` works even if `user` object doesn't exist:
At læse adressen med `user?.address` fungerer selvom `user` objektet ikke eksisterer:

```js run
let user = null;
Expand All @@ -115,76 +115,75 @@ alert( user?.address ); // undefined
alert( user?.address.street ); // undefined
```

Please note: the `?.` syntax makes optional the value before it, but not any further.
Bemærk: `?.`-syntaksen gør værdien før den valgfri, men ikke videre.

E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/undefined` (and returns `undefined` in that case), but that's only for `user`. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`.
F.eks. i `user?.address.street.name` tillader `?.` at `user` sikkert kan være `null/undefined` (og returnerer `undefined` i det tilfælde), men det gælder kun for `user`. Yderligere egenskaber tilgås på en almindelig måde. Hvis vi vil have nogle af dem til at være valgfrie, skal vi erstatte flere `.` med `?.`.

```warn header="Don't overuse the optional chaining"
We should use `?.` only where it's ok that something doesn't exist.
```warn header="Lad være med at overbruge valgfri kædning"
Vi bør kun bruge `?.` der, hvor det er i orden, at noget ikke eksisterer.

For example, if according to our code logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`.
For eksempel, hvis vores kodes logik kræver at `user` objektet eksisterer, men `address` er valgfri, så bør vi skrive `user.address?.street`, men ikke `user?.address?.street`.

Then, if `user` happens to be undefined, we'll see a programming error about it and fix it. Otherwise, if we overuse `?.`, coding errors can be silenced where not appropriate, and become more difficult to debug.
På den måde, hvis `user` tilfældigvis er undefined, vil vi se en programmeringsfejl om det og rette det. Ellers, hvis vi overbruger `?.`, kan kodefejl blive tavse, hvor det ikke er passende, og blive sværere at debugge.
```

````warn header="The variable before `?.` must be declared"
If there's no variable `user` at all, then `user?.anything` triggers an error:
````warn header="Variablen før `?.` skal være deklareret"
Hvis der slet ikke er nogen variabel `user`, vil `user?.anything` udløse en fejl:

```js run
// ReferenceError: user is not defined
user?.address;
```
The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables.
Variablen skal være deklareret (f.eks. `let/const/var user` eller som en funktionsparameter). Den valgfrie kædning fungerer kun for deklarerede variabler.
````

## Short-circuiting
## Kortslutning (Short-circuiting)

As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist.
Som nævnt tidligere stopper `?.` straks ("kortslutter") evalueringen, hvis venstredelen ikke eksisterer.

So, if there are any further function calls or operations to the right of `?.`, they won't be made.
Så hvis der er yderligere funktionskald eller operationer til højre for `?.`, vil de ikke blive udført.

For instance:
For eksempel:

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

user?.sayHi(x++); // no "user", so the execution doesn't reach sayHi call and x++
user?.sayHi(x++); // ingen "user", så udførelsen når ikke sayHi-kaldet og x++

alert(x); // 0, value not incremented
alert(x); // 0, værdi ikke inkrementeret
```

## Other variants: ?.(), ?.[]
## Andre varianter: ?.(), ?.[]

The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets.
Den valgfrie kædning `?.` er ikke en operator, men en særlig syntaks, der også fungerer med funktioner og firkantede parenteser.

For example, `?.()` is used to call a function that may not exist.

In the code below, some of our users have `admin` method, and some don't:
For eksempel bruges `?.()` til at kalde en funktion, der måske ikke eksisterer.

I koden nedenfor har nogle af vores brugere `admin`-metoden, og nogle har ikke:
```js run
let userAdmin = {
admin() {
alert("I am admin");
alert("Jeg er admin");
}
};

let userGuest = {};

*!*
userAdmin.admin?.(); // I am admin
userAdmin.admin?.(); // Jeg er admin
*/!*

*!*
userGuest.admin?.(); // nothing happens (no such method)
userGuest.admin?.(); // intet sker (metoden findes ikke)
*/!*
```

Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the `user` object exists, so it's safe read from it.
Her bruger vi i begge linjer først punktum (`userAdmin.admin`) til at få `admin`-egenskaben, fordi vi antager, at `user`-objektet eksisterer, så det er sikkert at læse fra det.

Then `?.()` checks the left part: if the `admin` function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors.
Derefter tjekker `?.()` venstredelen: hvis `admin`-funktionen findes, så kører den (det gælder for `userAdmin`). Ellers (for `userGuest`) stopper evalueringen uden fejl.

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.
`?.[]`-syntaksen fungerer også, hvis vi gerne vil bruge firkantede parenteser `[]` til at få adgang til egenskaber i stedet for punktum `.`. Ligesom i de tidligere tilfælde tillader det at læse en egenskab sikkert fra et objekt, der måske ikke eksisterer.

```js run
let key = "firstName";
Expand All @@ -199,35 +198,35 @@ alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined
```

Also we can use `?.` with `delete`:
Vi kan også bruge `?.` med `delete`:

```js run
delete user?.name; // delete user.name if user exists
delete user?.name; // slet user.name hvis user eksisterer
```

````warn header="We can use `?.` for safe reading and deleting, but not writing"
The optional chaining `?.` has no use on the left side of an assignment.
````warn header="Vi kan bruge `?.` til sikker læsning og sletning, men ikke skrivning"
Den valgfrie kædning `?.` har ingen effekt på venstresiden af en tildeling.

For example:
For eksempel:
```js run
let user = null;

user?.name = "John"; // Error, doesn't work
// because it evaluates to: undefined = "John"
user?.name = "John"; // Fejl, virker ikke
// fordi det evalueres til: undefined = "John"
```

````

## Summary
## Opsummering

The optional chaining `?.` syntax has three forms:
Den valgfrie kædning `?.`-syntaks har tre former:

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.method` exists, otherwise returns `undefined`.
1. `obj?.prop` -- returnerer `obj.prop` hvis `obj` eksisterer, ellers `undefined`.
2. `obj?.[prop]` -- returnerer `obj[prop]` hvis `obj` eksisterer, ellers `undefined`.
3. `obj.method?.()` -- kalder `obj.method()` hvis `obj.method` eksisterer, ellers returnerer `undefined`.

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.
Som vi kan se, er alle tre former enkle og ligetil at bruge. `?.` tjekker venstredelen for `null/undefined` og tillader evalueringen at fortsætte, hvis det ikke er tilfældet.

A chain of `?.` allows to safely access nested properties.
En kæde af `?.` tillader sikker adgang til indlejrede egenskaber.

Still, we should apply `?.` carefully, only where it's acceptable, according to our code logic, that the left part doesn't exist. So that it won't hide programming errors from us, if they occur.
Vi bør dog anvende `?.` med omtanke, kun hvor det er acceptabelt ifølge vores kodelogik, at venstredelen ikke eksisterer. Så det ikke skjuler programmeringsfejl for os, hvis de opstår.