Le chaînage optionnel ?. est un moyen sécurisé dâaccéder aux propriétés dâobjet imbriquées, même si une propriété intermédiaire nâexiste pas.
Le problème de la âpropriété non existanteâ
Si vous venez de commencer à lire le tutoriel et à apprendre JavaScript, peut-être que le problème ne vous a pas encore touché, mais câest assez courant.
à titre dâexemple, disons que nous avons des objets user qui contiennent les 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 :
let user = {}; // un utilisateur sans propriété "address"
alert(user.address.street); // Error!
Câest le résultat attendu. JavaScript fonctionne comme cela. Comme user.address est undefined, une tentative dâobtention de user.address.street échoue avec une erreur.
Dans de nombreux cas pratiques, nous préférerions obtenir undefined au lieu dâune erreur ici (signifiant â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écial, tel que document.querySelector('.elem'), et il renvoie null lorsquâil nây a pas ce type dâélément.
// document.querySelector('.elem') est nul s'il n'y a pas d'élément
let html = document.querySelector('.elem').innerHTML; // error if it's null
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 accepter simplement html = null comme résultat.
Comment peut-on le faire ?
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 :
let user = {}; // l'utilisateur n'a pas d'adresse
alert(user.address ? user.address.street : undefined);
Cela fonctionne, il nây a pas dâerreur⦠Mais câest assez inélégant. Comme vous pouvez le voir, "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.
let user = {}; // l'utilisateur n'a pas d'adresse
alert(user.address ? user.address.street ? user.address.street.name : null : null);
Câest juste horrible, on peut même avoir des problèmes pour comprendre un tel code.
Il existe une meilleure façon de lâécrire, en utilisant lâopérateur && :
let user = {}; // l'utilisateur n'a pas d'adresse
alert( user.address && user.address.street && user.address.street.name ); // undefined (no error)
Et le chemin complet vers la propriété garantit que tous les composants existent (sinon, lâévaluation sâarrête), mais nâest pas non plus idéal.
Comme vous pouvez le voir, 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 facultatif ?. a été ajouté au langage. Pour résoudre ce problème une fois pour toutes !
Chaînage optionnel
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 brièveté, nous dirons que quelque chose âexisteâ si ce nâest pas ânullâ et non âundefinedâ.
En dâautres termes, value?.prop :
- est identique Ã
value.propsivalueexiste, - sinon (lorsque
valueestundefined/null), il renvoieundefined.
Voici le moyen sûr dâaccéder à user.address.street en utilisant ?. :
let user = {}; // l'utilisateur n'a pas d'adresse
alert( user?.address?.street ); // undefined (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; // sera undefined 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 :
let user = null;
alert( user?.address ); // undefined
alert( user?.address.street ); // undefined
Remarque : 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 en toute sécurité null/undefined (et renvoie undefined dans ce cas), mais ce nâest que pour user. Dâautres propriétés sont accessibles de manière régulière. Si nous voulons que certaines dâentre elles soient optionnelles, alors nous devrons remplacer plus de . par ?..
Nous ne devrions utiliser ?. que là où il est normal que quelque chose nâexiste pas.
Par exemple, si selon notre logique de codage, lâobjet user doit exister, mais que address est facultatif, 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 nous la corrigerons. Sinon, si nous abusons de ?., les erreurs de codage peuvent être réduites au silence là où cela nâest pas approprié et devenir plus difficiles à déboguer.
?. doit être déclaréeSâil nây a pas du tout de variable user, alors user?.anything déclenche une erreur :
// ReferenceError: user is not defined
user?.address;
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.
Court-circuit
Comme il a été dit précédemment, le ?. arrête immédiatement (âcourt-circuiteâ) lâévaluation si la partie gauche nâexiste pas.
Ainsi, sâil y a dâautres appels de fonction ou opérations à droite de ?., elles ne seront pas effectuées.
Par exemple :
let user = null;
let x = 0;
user?.sayHi(x++); // pas de "user", donc l'exécution n'atteint pas l'appel sayHi et x++
alert(x); // 0, la valeur n'est pas incrémenté
Autres variantes : ?.(), ?.[]
?. nâest pas un opérateur, mais une construction syntaxique particulière qui fonctionne aussi avec les appels de fonction et les crochets.
Par exemple, ?.() est utilisé pour exécuter une fonction seulement si elle existe.
Ainsi dans cet exemple la méthode admin nâexiste pas pour tout le monde :
let userAdmin = {
admin() {
alert("I am admin");
}
};
let userGuest = {};
userAdmin.admin?.(); // I am admin
userGuest.admin?.(); // rien ne se passe (aucune méthode de ce nom)
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é.
Puis ?.() 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 voulons utiliser des crochets [] pour accéder aux propriétés au lieu du point .. Similaire aux cas précédents, il permet de lire en toute sécurité une propriété à partir dâun objet qui peut ne pas exister.
let key = "firstName";
let user1 = {
firstName: "John"
};
let user2 = null;
alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined
Nous pouvons également utiliser ?. avec delete :
delete user?.name; // supprime user.name si user existe
?. pour lire et supprimer en toute sécurité, mais pas pour écrireLe chaînage optionnel ?. nâa aucune utilité sur le côté gauche dâune affectation :
Par exemple :
let user = null;
user?.name = "John"; // Erreur, ne fonctionne pas
// car il évalue : undefined = "John"
Ce nâest tout simplement pas si intelligent.
Résumé
Le chaînage optionnel â?.â a trois formes :
obj?.propâ retourneobj.propsiobjexiste, sinonundefined.obj?.[prop]â retourneobj[prop]siobjexiste, sinonundefined.obj.method?.()â appelobj.method()siobj.methodexiste, sinon retourneundefined.
Comme nous pouvons le voir, tous sont 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.
Néanmoins, nous devons appliquer ?. avec précaution, uniquement là où il est acceptable, selon la logique de notre code, que la partie gauche nâexiste pas. Pour quâil ne nous cache pas les erreurs de programmation, si elles se produisent.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâ¦)