This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist.
Il concatenamento opzionale (optional chaining), `?.`, è un modo sicuro di accedere alle proprietà annidate di un oggetto, anche nel caso in cui una proprietà intermedia non dovesse esistere.
## The "non-existing property" problem
## Il problema della "proprietà inesistente"
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.
Se avete appena cominciato a leggere il tutorial e a imparare JavaScript, forse questo problema non lo avete ancora affrontato, ma è piuttosto comune.
As an example, let's say we have `user` objects that hold the information about our users.
Ad esempio, ipotizziamo di avere un oggetto `user`, in cui sono memorizzate le informazioni relative ai nostri utenti.
Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them.
La maggior parte dei nostri utenti possiedono l'indirizzo nella proprietà `user.address`, la via in `user.address.street`, ma qualcuno potrebbe non averle fornite.
In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error:
In questo caso, quando proviamo ad accedere a `user.address.street`, e l'utente non possiede un indirizzo, otterremo un errore:
```js run
let user = {}; // a user without "address" property
let user = {}; // un utente senza la proprietà "address"
alert(user.address.street); // Error!
alert(user.address.street); // Errore!
```
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.
Questo è il risultato che ci si aspetta. JavaScript funziona in questo modo. Se `user.address` è `undefined`, un tentativo di accesso a `user.address.street` fallirà con un errore.
In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street").
Nella maggior parte dei casi, preferiremmo avere `undefined` piuttosto di un errore (con il significato "nessuna via").
...And another example. In the 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.
... Un altro esempio. Il metodo `document.querySelector('.elem')` ritorna un oggetto che corrisponde ad un elemento della pagina web, che ritorna `null` quando l'elemento non esite.
```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') è null se non esiste l'elemento
let html = document.querySelector('.elem').innerHTML; // errore se è null
```
Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` 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.
Di nuovo, se un elemente non esiste, otterremo un errore nel tentativo di accedere a `.innerHTML` di `null`. In alcuni casi, in cui l'assenza di un elemento è normale, vorremo evitare l'errore e accettare come risultato `html = null`.
How can we do this?
Come possiamo farlo?
The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this:
La soluzione più ovvia sarebbe di controllare il valore utilizzando `if` o l'operatore condizionale `?`, prima di accedere alle proprietà, come nell'esempio:
It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. For more deeply nested properties, that becomes a problem as more repetitions are required.
Funziona, nessun errore... Ma è poco elegante. Come potete vedere , `"user.address"` appare due volte nel codice. Per proprietà molto più annidate, potrebbe diventare un problema, in quanto saranno necessarie molte più ripetizioni.
E.g. let's try getting `user.address.street.name`.
Ad esempio, proviamo a recuperare il valore di `user.address.street.name`.
We need to check both `user.address` and `user.address.street`:
Dobbiamo verificare sia `user.address` che `user.address.street`:
AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal.
Concatenare con `&&` l'intero percorso verso la proprietà ci assicura che tutti i componenti esistano (in caso contrario, la valutazione si interrompe), ma non è comunque l'ideale.
As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times.
Come potete vedere, il nome della proprietà è ancora duplicato nel codice. Ad esempio, nel codice sopra, `user.address` è ripetuto tre volte.
That's why the optional chaining `?.` was added to the language. To solve this problem once and for all!
Questo è il motivo per cui la concatenazione opzionale `?.` è stata aggiunta al linguaggio. Per risolvere questo problema una volta per tutte!
## Optional chaining
## Concatenazione opzionale
The optional chaining `?.` stops the evaluation if the value before `?.` is `undefined` or `null` and returns `undefined`.
La concatenazione opzionale `?.` interrompe la valutazione se il valore prima di `?.` è `undefined` o `null`, e ritorna `undefined`.
**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.**
**D'ora in poi in questo articolo, per brevità, diremo che qualcosa "esiste" se non è ne `null` né `undefined`.**
In other words, `value?.prop`:
- works as `value.prop`, if `value` exists,
- otherwise (when `value` is `undefined/null`) it returns `undefined`.
In altre parole, `value?.prop`:
- funziona come `value.prop`, se `value` esiste,
- altrimenti (quando `value` è `undefined/null`) ritorna `undefined`.
Here's the safe way to access `user.address.street` using `?.`:
Vediamo un modo sicuro per accedere a `user.address.street` utilizzando `?.`:
```js run
let user = {}; // user has no address
let user = {}; // user non possiede l'address
alert( user?.address?.street ); // undefined (no error)
Please note: the `?.` syntax makes optional the value before it, but not any further.
Da notare: la sintassi `?.` rende opzionale il valore che la precede, nulla di più.
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 `?.`.
Ad esempio in `user?.address.street.name` il costrutto `?.` permette alla proprietà `user` di essere `null/undefined` in sicurezza (e ritornare `undefined` in questo caso), ma questo vale solamente per `user`. Si accederà alle altre proprietà normalmente. Se vogliamo che anche altre proprietà siano opzionali, dobbiamo rimpiazzare `.` con `?.`.
```warn header="Don't overuse the optional chaining"
We should use `?.` only where it's ok that something doesn't exist.
```warn header="Non abusate della concatenazione opzionale"
Dovremmo utilizzare `?.` solamente quando va bene che una proprietà possa non esistere.
For example, if according to our coding logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`.
Ad esempio, considerando la logica del nostro codice, l'oggetto `user` deve necessariamente esistere, mentre `address` è opzionale, quindi dovremmo scrivere `user.address?.street`, non `user?.address?.street`.
So, if `user` happens to be undefined due to a mistake, we'll see a programming error about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug.
Quindi, se `user` dovesse essere `undefined` per errore, otterremo un errore e potremmo sistemarlo. Altrimenti, gli errori di programmazione potrebbero essere silenziati in modo non appropriato, rendendo il debug molto difficile.
```
````warn header="The variable before `?.` must be declared"
If there's no variable `user` at all, then `user?.anything` triggers an error:
````warn header="La variabile che precede `?.` deve essere dichiarata"
Se non esiste alcuna variabile `user`, allora `user?.anything` provocherà un errore:
```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.
La variabile deve essere dichiarata (ad esempio come `let/const/var user` o come parametro di funzione). La concatenazione opzionale funziona solamente con le variabili dichiarate.
````
## Short-circuiting
## Corto circuito
As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist.
Come detto in precedenza, il costrutto `?.` interrompe immediatamente (manda in "corto circuito") la valutazione se la proprietà a destra non esiste.
So, if there are any further function calls or side effects, they don't occur.
Quindi, nel caso ci siano ulteriori chiamate a funzione o side-effects, questi non verranno elaborati.
For instance:
Ad esempio:
```js run
let user = null;
let x = 0;
user?.sayHi(x++); // no "sayHi", so the execution doesn't reach x++
user?.sayHi(x++); // non esiste "sayHi", quindi l'esecuzione non raggiungerà x++
alert(x); // 0, value not incremented
alert(x); // 0, valore non incrementato
```
## Other variants: ?.(), ?.[]
## Altre varianti: ?.(), ?.[]
The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets.
La concatenazione opzionale `?.` non è un operatore, ma uno speciale costrutto sintattico, che funziona anche con le funzioni e le parentesi quadre.
For example, `?.()` is used to call a function that may not exist.
Ad esempio, `?.()` viene utilizzato per invocare una funzione che potrebbe non esistere.
In the code below, some of our users have `admin` method, and some don't:
Nel codice sotto, alcuni dei nostri utenti possiedono il metodo `admin`, mentre altri no:
```js run
let userAdmin = {
Expand All
@@ -162,15 +162,15 @@ userAdmin.admin?.(); // I am admin
*/!*
*!*
userGuest.admin?.(); // nothing (no such method)
userGuest.admin?.(); // niente (il metodo non esiste)
*/!*
```
Here, in both lines we first use the dot (`user1.admin`) to get `admin` property, because the user object must exist, so it's safe read from it.
Qui, in entrambe le righe, come prima cosa abbiamo utilizzato il punto (`user1.admin`) per ottenere la proprietà `admin`, poiché l'oggetto `user` deve necessariamente esistere, quindi l'accesso è sicuro.
Then `?.()` checks the left part: if the admin function exists, then it runs (that's so for `user1`). Otherwise (for `user2`) the evaluation stops without errors.
Successivamente `?.()` controlla la parte sinistra: se la funzione `admin` esiste, allora viene eseguita (ciò che accade con `user1`). Altrimenti (con `user2`) la valutazione si interrompe senza errori.
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.
La sintassi `?.` funziona anche con le parentesi `[]` (invece del punto `.`). Come nei casi precedenti, possiamo accedere con sicurezza ad una proprietà di un oggetto che potrebbe non esistere.
```js run
let key = "firstName";
Expand All
@@ -185,36 +185,36 @@ alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined
```
Also we can use `?.` with `delete`:
Possiamo anche utilizzare `?.` con `delete`:
```js run
delete user?.name; // delete user.name if user exists
delete user?.name; // cancella user.name se l'utente esiste
```
````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="Possiamo utilizzare `?.` per l'accesso e la rimozione sicura, ma non per la scrittura"
La concatenazione opzionale `?.` non ha alcun significato alla sinistra di un'assegnazione.
For example:
Ad esempio:
```js run
let user = null;
user?.name = "John"; // Error, doesn't work
// because it evaluates to undefined = "John"
user?.name = "John"; // Errore, non funziona
// poiché valuta undefined = "John"
```
It's just not that smart.
Non è cosi intelligente.
````
## Summary
## Riepilogo
The optional chaining `?.` syntax has three forms:
La concatenazione opzionale `?.` ha tre forme:
1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`.
2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `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.
Come possiamo vedere, le tre forme sono semplici da utilizzare. Il costrutto `?.` verifica che la parte sinistra non sia `null/undefined`; se non lo è, permette alla valutazione di proseguire, altrimenti interrompe immediatamente la valutazione.
A chain of `?.` allows to safely access nested properties.
La concatenazione di `?.` permette di accedere in sicurezza a proprietà annidate.
Still, we should apply `?.` carefully, only where it's acceptable that the left part doesn't exist. So that it won't hide programming errors from us, if they occur.
In ogni caso, dovremmo applicare `?.` con prudenza, solamente nei casi in cui è accettabile che la parte sinistra possa non esistere. In questo modo evitiamo di nascondere errori di programmazione, nel caso ce ne siano.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Optional chaining '?.' #187
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
Uh oh!
There was an error while loading. Please reload this page.
Optional chaining '?.' #187
Filter by extension
Viewed files
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing