Question 1Écris let couponCode; et lis-la sans assigner de valeur. Quelle est la valeur de la variable ?
null et undefined — lire en sécurité avec ?. et ??
La différence entre null et undefined, puis lire un objet imbriqué sans erreur et poser un défaut sûr.
En affichant des données de commande d'un serveur, tu vas tomber sur une adresse jamais renseignée, ou un mode de paiement pas encore choisi. JavaScript a deux valeurs pour cet état « rien n'est là » — undefined et null — et une lecture échouée arrête le traitement avec un TypeError.
Cet article couvre la différence entre les deux, la lecture à travers une étape manquante sans s'arrêter, et l'application d'une valeur par défaut quand quelque chose manque.
Les 2 valeurs signifiant que rien n'est là — undefined et null
undefined (une valeur que JavaScript remplit automatiquement quand rien n'a encore été assigné) apparaît de lui-même — tu n'as pas besoin de l'assigner toi-même. Tu l'as déjà vu revenir en lisant au-delà de la fin d'un tableau ou une clé d'objet non enregistrée, et une variable seulement déclarée tombe aussi dans cette catégorie.
- Une variable seulement déclarée, jamais assignée, comme
let couponCode; - Une clé non enregistrée sur un objet, comme
order.customer(vu plus tôt) - Un index hors limites sur un tableau à 2 éléments, comme
tags[5](vu plus tôt)
null (une valeur que l'auteur assigne délibérément pour signaler le vide), en revanche, n'apparaît jamais de lui-même. Quand tu veux que l'absence même d'une valeur soit une donnée — « aucune adresse de livraison choisie pour l'instant », « aucun coupon appliqué » — tu assignes null toi-même.
Le JSON qui revient d'une API peut aussi porter null pour signaler qu'un champ est vide.
Puisque ce sont des valeurs différentes, === renvoie false en les comparant. ==, cependant, traite les deux comme identiques et renvoie true.
Quand tu écris une vérification, soit sois précis sur laquelle des deux tu attends et vérifie juste ce côté, comme dans === null, soit confie ça entièrement à ?. et ??, couverts à partir d'ici.
let couponCode; // seulement déclarée, pas de valeur assignée
console.log(couponCode); // undefined
const order = { orderId: "ORD-1105", total: 12800 };
console.log(order.customer); // undefined (une clé non enregistrée)
const tags = ["Limité", "Précommande"];
console.log(tags[5]); // undefined (un index hors limites)
// null est assigné par l'auteur
let shippingAddress = null; // aucune adresse de livraison choisie pour l'instant
console.log(shippingAddress); // null
console.log(shippingAddress === undefined); // false (ce sont des valeurs différentes)
console.log(shippingAddress == undefined); // true (== les traite comme identiques)
Ne pas s'arrêter quand une étape imbriquée manque — le chaînage optionnel ?.
Les données renvoyées par une API n'ont pas toujours tous les champs remplis. Du code qui lit en profondeur, comme order.customer.address.city, s'arrête dès qu'une seule commande manque d'un address en cours de route.
C'est là que tu veux que la lecture elle-même n'échoue pas — qu'elle continue comme « rien là » à la place.
Quand order.customer.address vaut undefined, essayer de lire .city après ça lève TypeError: Cannot read properties of undefined (reading 'city'). Le 1er niveau de lecture se passe bien, mais ça s'arrête au 2e.
C'est à ça que sert le chaînage optionnel (l'opérateur ?., qui renvoie undefined sans lire plus loin si le côté gauche est null ou undefined). Écris address?.city, et .city ne se lit que quand address a une valeur — sinon, la lecture s'arrête là et renvoie undefined.
Quand tu passes une clé à travers [], écris-la comme ?.[field].
const order = {
orderId: "ORD-1105",
customer: { name: "Ryan Cole" },
};
// address manque, donc lire city après ça s'arrêterait
// console.log(order.customer.address.city);
// TypeError: Cannot read properties of undefined (reading 'city')
// Insère ?. et la lecture s'arrête, renvoyant undefined
console.log(order.customer.address?.city); // undefined
// Là où il y a une valeur, ça continue normalement
console.log(order.customer.name); // Ryan Cole
// Passe une clé à travers une variable avec ?.[]
const field = "city";
console.log(order.customer.address?.[field]); // undefined
Utilise-le seulement là où un champ peut légitimement manquer
Mets ?. à chaque étape, et même un nom de clé mal orthographié glisse comme undefined sans lever d'erreur. Passe-le sur les champs garantis d'être là, et utilise-le seulement juste avant un champ qui peut légitimement manquer — ainsi les erreurs que tu veux vraiment attraper arrêtent toujours l'exécution.
Mettre en place une valeur par défaut — ?? vs ||
Plutôt que d'afficher un simple undefined quand un champ manque, tu voudras généralement afficher une valeur par défaut — « Invité », « 20 articles ».
Utilise || pour ça, cependant, et parfois une valeur réellement présente se fait remplacer par la valeur par défaut quand même. Un compte de stock de 0, ou un champ de note vide, en sont des exemples.
null et undefined ensemble s'appellent nullish. Utilise l'opérateur de coalescence des nuls (l'opérateur ??, qui renvoie le côté droit seulement quand le côté gauche est nullish), et 0, une chaîne vide, ou false restent exactement comme ils sont.
|| renvoie le côté droit dès que la gauche est falsy, donc ça ne peut pas distinguer « il n'y a pas de valeur » de « la valeur est 0 ». Quand ton but est d'appliquer une valeur par défaut, ?? évite le remplacement non voulu.
0. ?? remplace seulement null et undefined, donc 0 reste la valeur.| Valeur à gauche | Ce que || renvoie | Ce que ?? renvoie |
|---|---|---|
| null | la valeur par défaut | la valeur par défaut |
| undefined | la valeur par défaut | la valeur par défaut |
| 0 | la valeur par défaut | reste 0 |
| chaîne vide | la valeur par défaut | reste une chaîne vide |
| false | la valeur par défaut | reste false |
const settings = { displayName: null, itemsPerPage: 0 };
// ?? renvoie le côté droit seulement quand la gauche est null ou undefined
console.log(settings.displayName ?? "Invité"); // Invité
console.log(settings.itemsPerPage ?? 20); // 0 (reste tel quel)
// || renvoie le côté droit dès que la gauche est falsy, donc même 0 se fait remplacer
console.log(settings.itemsPerPage || 20); // 20
// Une clé non enregistrée retombe sur la valeur par défaut dans les deux cas
console.log(settings.language ?? "fr"); // fr
console.log(settings.language || "fr"); // fr
Remarque qu'écrire ?? et || côte à côte sans parenthèses, comme dans displayName ?? "Invité" || "Anonyme", est une erreur de syntaxe — JavaScript ne peut pas décider lequel évaluer en premier. Pour utiliser les deux, sépare-les avec des parenthèses, comme dans (displayName ?? "Invité") || "Anonyme".
Ne laisse pas une valeur par défaut effacer 0 ou une chaîne vide
Un compte de stock de 0, un taux de réduction de 0, une note vide — tout ça compte comme « il y a une valeur ». Applique une valeur par défaut avec ||, et puisque ce sont des valeurs falsy, elles se font remplacer par la valeur par défaut, créant un décalage comme un article en rupture de stock qui s'affiche comme disponible. Utilise ?? quand tout ce qui t'importe, c'est si une valeur est présente du tout.
Ne pas appeler quelque chose qui n'est pas là — l'appel ?.()
Dans le traitement de commandes, tu vas parfois ranger un « quoi faire en cas de succès » et un « quoi faire en cas d'échec » dans un objet, en les appelant au besoin. Appelle un champ qui n'a rien de configuré, cependant, et ça s'arrête avec TypeError: handlers.onError is not a function — donc tu as besoin d'un moyen de l'appeler seulement quand c'est réellement là.
La fonction couverte dans l'article 3 peut aussi vivre à l'intérieur d'un objet comme valeur d'une propriété. Le () => ... dans l'exemple suivant est une syntaxe pour créer une fonction sur le coup — cette syntaxe elle-même est couverte dans la catégorie syntaxe, donc ici concentre-toi juste sur comment le résultat change selon qu'une fonction est présente dans la propriété.
Appelle une propriété qui pourrait contenir une fonction comme handlers.onError?.(), et quand onError est null ou undefined, l'appel se fait sauter et undefined revient à la place.
undefined sans rien appeler si c'est null. Appelle-la sans ?. et ça s'arrête avec un TypeError.const handlers = {
onSuccess: () => console.log("Commande confirmée"),
onError: null,
};
// Une fonction est là, donc elle se fait appeler
handlers.onSuccess?.(); // Commande confirmée
// C'est null, donc l'appel est sauté et undefined revient
console.log(handlers.onError?.()); // undefined
// Appeler sans ?. arrête l'exécution
// handlers.onError();
// TypeError: handlers.onError is not a function
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Quand le côté gauche de ?. est null ou undefined, que se passe-t-il pour le reste de la chaîne ?
Question 3Avec const discountRate = 0;, que renvoient respectivement discountRate || 5 et discountRate ?? 5 ?