Un ajout récent
Il s'agit d'un ajout récent à la langue. Les anciens navigateurs peuvent avoir besoin de polyfills.
Le chaînage optionnel ?.
est un moyen sûr d'accéder aux propriétés d'objets imbriqués, même si aucune propriété intermédiaire n'existe.
Si vous venez de commencer à lire le didacticiel et à apprendre JavaScript, le problème ne vous a peut-être pas encore touché, mais il est assez courant.
À titre d'exemple, disons que nous avons des objets user
qui contiennent des informations sur nos utilisateurs.
La plupart de nos utilisateurs ont des adresses dans la propriété user.address
, avec la rue user.address.street
, mais certains ne les ont pas fournies.
Dans ce cas, lorsque nous essayons d'obtenir user.address.street
et que l'utilisateur se trouve sans adresse, nous obtenons une erreur :
laissez l'utilisateur = {} ; // un utilisateur sans propriété "adresse" alerte (utilisateur.adresse.rue); // Erreur!
C'est le résultat attendu. JavaScript fonctionne comme ça. Comme user.address
undefined
, une tentative d'obtention user.address.street
échoue avec une erreur.
Dans de nombreux cas pratiques, nous préférerions avoir ici une undefined
plutôt qu'une erreur (ce qui signifie « pas de rue »).
…et un autre exemple. Dans le développement Web, nous pouvons obtenir un objet qui correspond à un élément de page Web à l'aide d'un appel de méthode spéciale, tel que document.querySelector('.elem')
, et il renvoie null
lorsqu'un tel élément n'existe pas.
// document.querySelector('.elem') est nul s'il n'y a aucun élément laissez html = document.querySelector('.elem').innerHTML; // erreur si c'est nul
Encore une fois, si l'élément n'existe pas, nous obtiendrons une erreur lors de l'accès à la propriété .innerHTML
de null
. Et dans certains cas, lorsque l'absence de l'élément est normale, nous aimerions éviter l'erreur et simplement accepter html = null
comme résultat.
Comment pouvons-nous faire cela ?
La solution évidente serait de vérifier la valeur en utilisant if
ou l'opérateur conditionnel ?
, avant d'accéder à sa propriété, comme ceci :
laissez l'utilisateur = {} ; alert(user.address ? user.address.street : non défini);
Ça marche, il n'y a pas d'erreur… Mais c'est assez inélégant. Comme vous pouvez le constater, le "user.address"
apparaît deux fois dans le code.
Voici à quoi ressemblerait la même chose pour document.querySelector
:
let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null;
Nous pouvons voir que l'élément de recherche document.querySelector('.elem')
est en fait appelé deux fois ici. Pas bon.
Pour les propriétés plus profondément imbriquées, cela devient encore plus laid, car davantage de répétitions sont nécessaires.
Par exemple, récupérons user.address.street.name
de la même manière.
laissez l'utilisateur = {} ; // l'utilisateur n'a pas d'adresse alert(user.address ? user.address.street ? user.address.street.name : null : null);
C'est tout simplement horrible, on peut même avoir du mal à comprendre un tel code.
Il existe une meilleure façon de l'écrire, en utilisant l'opérateur &&
:
laissez l'utilisateur = {} ; // l'utilisateur n'a pas d'adresse alert( user.address && user.address.street && user.address.street.name ); // non défini (pas d'erreur)
ET l'ensemble du chemin d'accès à la propriété garantit que tous les composants existent (sinon, l'évaluation s'arrête), mais ce n'est pas non plus idéal.
Comme vous pouvez le constater, les noms de propriétés sont toujours dupliqués dans le code. Par exemple, dans le code ci-dessus, user.address
apparaît trois fois.
C'est pourquoi le chaînage optionnel ?.
a été ajouté à la langue. Pour résoudre ce problème une fois pour toutes !
Le chaînage optionnel ?.
arrête l'évaluation si la valeur avant ?.
est undefined
ou null
et renvoie undefined
.
Plus loin dans cet article, par souci de concision, nous dirons que quelque chose « existe » s'il n'est ni null
ni undefined
.
En d'autres termes, value?.prop
:
fonctionne comme value.prop
, si value
existe,
sinon (lorsque value
est undefined/null
), elle renvoie undefined
.
Voici le moyen sûr d’accéder à user.address.street
en utilisant ?.
:
laissez l'utilisateur = {} ; // l'utilisateur n'a pas d'adresse alert( utilisateur?.adresse?.rue ); // non défini (pas d'erreur)
Le code est court et propre, il n’y a aucune duplication.
Voici un exemple avec document.querySelector
:
let html = document.querySelector('.elem')?.innerHTML; // ne sera pas défini s'il n'y a pas d'élément
La lecture de l'adresse avec user?.address
fonctionne même si l'objet user
n'existe pas :
laissez l'utilisateur = null ; alert( utilisateur?.adresse ); // non défini alerte( utilisateur?.adresse.rue ); // non défini
Attention : le ?.
la syntaxe rend facultative la valeur qui la précède, mais pas plus.
Par exemple, dans user?.address.street.name
le ?.
permet à user
d'être null/undefined
en toute sécurité (et renvoie undefined
dans ce cas), mais c'est uniquement pour user
. D'autres propriétés sont accessibles de manière régulière. Si nous voulons que certains d’entre eux soient facultatifs, nous devrons alors en remplacer davantage .
avec ?.
.
N'abusez pas du chaînage optionnel
Nous devrions utiliser ?.
seulement là où c'est normal que quelque chose n'existe pas.
Par exemple, si, selon notre logique de code, l'objet user
doit exister, mais address
est facultative, alors nous devrions écrire user.address?.street
, mais pas user?.address?.street
.
Ensuite, si user
n'est pas défini, nous verrons une erreur de programmation à ce sujet et la corrigerons. Sinon, si on abuse de ?.
, les erreurs de codage peuvent être réduites au silence lorsqu'elles ne sont pas appropriées et devenir plus difficiles à déboguer.
La variable avant ?.
doit être déclaré
S'il n'y a aucune variable user
, alors user?.anything
déclenche une erreur :
// ReferenceError : l'utilisateur n'est pas défini utilisateur?.adresse ;
La variable doit être déclarée (par exemple let/const/var user
ou en tant que paramètre de fonction). Le chaînage facultatif ne fonctionne que pour les variables déclarées.
Comme cela a été dit précédemment, le ?.
arrête immédiatement (« court-circuite ») l'évaluation si la partie gauche n'existe pas.
Donc, s’il y a d’autres appels de fonction ou opérations à droite de ?.
, ils ne seront pas fabriqués.
Par exemple:
laissez l'utilisateur = null ; soit x = 0 ; utilisateur?.sayHi(x++); // pas d'"utilisateur", donc l'exécution n'atteint pas l'appel sayHi et x++ alerte(x); // 0, valeur non incrémentée
Le chaînage optionnel ?.
n'est pas un opérateur, mais une construction syntaxique spéciale, qui fonctionne également avec les fonctions et les crochets.
Par exemple, ?.()
est utilisé pour appeler une fonction qui n'existe peut-être pas.
Dans le code ci-dessous, certains de nos utilisateurs disposent d'une méthode admin
, et d'autres non :
laissez userAdmin = { administrateur() { alert("Je suis administrateur"); } } ; laissez userGuest = {} ; userAdmin.admin?.(); // Je suis administrateur userGuest.admin?.(); // rien ne se passe (aucune méthode de ce type)
Ici, dans les deux lignes, nous utilisons d'abord le point ( userAdmin.admin
) pour obtenir la propriété admin
, car nous supposons que l'objet user
existe, il peut donc être lu en toute sécurité.
Ensuite ?.()
vérifie la partie gauche : si la fonction admin
existe, alors elle s'exécute (c'est le cas pour userAdmin
). Sinon (pour userGuest
) l'évaluation s'arrête sans erreur.
La syntaxe ?.[]
fonctionne également si nous souhaitons utiliser des crochets []
pour accéder aux propriétés au lieu de dot .
. Semblable aux cas précédents, il permet de lire en toute sécurité une propriété à partir d’un objet qui n’existe peut-être pas.
let key = "prénom"; laissez utilisateur1 = { prénom: "John" } ; laissez user2 = null ; alerte( utilisateur1?.[clé] ); // John alerte( utilisateur2?.[clé] ); // non défini
Nous pouvons également utiliser ?.
avec delete
:
supprimer l'utilisateur ?.nom ; // supprime user.name si l'utilisateur existe
Nous pouvons utiliser ?.
pour lire et supprimer en toute sécurité, mais pas pour écrire
Le chaînage optionnel ?.
n'a aucune utilité sur le côté gauche d'une affectation.
Par exemple:
laissez l'utilisateur = null ; utilisateur?.name = "John"; // Erreur, ça ne marche pas // car il donne la valeur : undefined = "John"
Le chaînage optionnel ?.
la syntaxe a trois formes :
obj?.prop
– renvoie obj.prop
si obj
existe, sinon undefined
.
obj?.[prop]
– renvoie obj[prop]
si obj
existe, sinon undefined
.
obj.method?.()
– appelle obj.method()
si obj.method
existe, sinon renvoie undefined
.
Comme nous pouvons le voir, ils sont tous simples et simples à utiliser. Le ?.
vérifie la partie gauche pour null/undefined
et permet à l'évaluation de se poursuivre si ce n'est pas le cas.
Une chaîne de ?.
permet d'accéder en toute sécurité aux propriétés imbriquées.
Pourtant, nous devrions appliquer ?.
soigneusement, seulement là où il est acceptable, selon notre logique de code, que la partie gauche n'existe pas. Pour qu'il ne nous cache pas les erreurs de programmation, si elles surviennent.