Question 1Avec const addFee = (price, fee = 500) => price + fee;, que renvoie addFee(1000, undefined) ?
Paramètres par défaut et du reste — valeurs de repli et arguments restants
Paramètres par défaut, paramètres du reste qui regroupent les arguments dans un tableau, et objet options.
Certains arguments reçoivent presque toujours la même valeur, comme des frais de port ou un taux de TVA. Si tu en oublies un, aucune erreur ne s'affiche : tu ne t'en aperçois que lorsque undefined apparaît dans le texte affiché.
Cet article présente les paramètres par défaut, qui fixent la valeur utilisée quand un argument est omis, les paramètres du reste, qui regroupent un nombre quelconque d'arguments, et le motif options, qui transmet des réglages dans un seul objet.
Rendre un argument facultatif — les paramètres par défaut
Imagine une fonction qui prépare la réservation d'une salle de réunion : la durée est presque toujours d'une heure, et la disposition presque toujours en classe. Si tu dois quand même écrire les trois arguments à chaque appel, la seule valeur que tu veux vraiment changer se perd dans l'appel.
Un paramètre par défaut (une façon de fixer à l'avance la valeur à utiliser quand un argument n'est pas transmis) s'écrit en ajoutant = dans la liste des paramètres, comme dans hours = 1. Un paramètre qui a une valeur par défaut peut être omis à l'appel.
// La valeur par défaut s'écrit en ajoutant « = valeur » dans la liste des paramètres
const reserveRoom = (roomName, hours = 1, layout = "classe") => {
return `${roomName} / ${hours} h / ${layout}`;
};
// Si tu omets le 3e, la valeur par défaut "classe" est utilisée
console.log(reserveRoom("Salle A", 2)); // Salle A / 2 h / classe
// Là où tu passes une valeur, la valeur par défaut n'est pas utilisée
console.log(reserveRoom("Salle A", 2, "en U")); // Salle A / 2 h / en U
// Si tu omets aussi le 2e, les deux valeurs par défaut sont utilisées
console.log(reserveRoom("Salle A")); // Salle A / 1 h / classe
reserveRoom("Salle A", 2) position par position. Même avec une valeur par défaut, rien ne change si une valeur est transmise.Tu ne peux omettre des arguments qu'en partant de la droite : place donc les paramètres qui ont une valeur par défaut en dernier. Même si tu veux seulement changer le 3e argument, tu dois écrire une valeur en 2e position.
Ce que reçoit un argument non transmis — undefined et valeurs par défaut
Si tu omets l'argument d'un paramètre sans valeur par défaut, le code qui l'utilise dans un calcul ou une chaîne s'exécute quand même. Comme rien ne s'arrête, tu te retrouves ensuite à chercher quel appel a oublié de le transmettre.
Un paramètre qui ne reçoit pas d'argument vaut undefined. La valeur par défaut n'est utilisée que si l'argument vaut undefined : si tu passes null, 0 ou une chaîne vide, c'est la valeur transmise qui est utilisée.
const notifyStatus = (orderId, status = "Reçue") => `${orderId}: ${status}`;
// Omettre l'argument ou passer undefined donne la valeur par défaut dans les deux cas
console.log(notifyStatus("A-1021")); // A-1021: Reçue
console.log(notifyStatus("A-1021", undefined)); // A-1021: Reçue
// null compte comme une valeur transmise : la valeur par défaut n'est pas utilisée
console.log(notifyStatus("A-1021", null)); // A-1021: null
// Un paramètre omis sans valeur par défaut reçoit undefined
const plainStatus = (orderId, status) => `${orderId}: ${status}`;
console.log(plainStatus("A-1021")); // A-1021: undefined
status omis reçoit undefined, donc l'expression par défaut s'exécute. null est traité comme une valeur transmise : la valeur par défaut ne s'applique pas.Le tableau ci-dessous montre, pour chaque deuxième argument passé à notifyStatus, la valeur que reçoit status et ce qui s'affiche. Passer undefined donne le même résultat qu'omettre l'argument, alors que null s'affiche tel quel, exactement comme une chaîne transmise.
| Appel | Valeur de status | Affichage |
|---|---|---|
| notifyStatus("A-1021") | La valeur par défaut, Reçue | A-1021: Reçue |
| notifyStatus("A-1021", "Expédiée") | Expédiée | A-1021: Expédiée |
| notifyStatus("A-1021", undefined) | La valeur par défaut, Reçue | A-1021: Reçue |
| notifyStatus("A-1021", null) | null | A-1021: null |
Si tu passes null, la valeur par défaut est ignorée
null est une valeur qui signifie « vide volontairement » : une valeur par défaut dans la liste des paramètres ne la remplace pas. Si tu veux la valeur de repli même quand la réponse d'une API contient null, ne mets pas de valeur par défaut sur le paramètre et utilise plutôt ?? dans la fonction, comme dans const shown = status ?? "Reçue";.
Regrouper un nombre variable d'arguments — les paramètres du reste
Certaines fonctions reçoivent un nombre de valeurs différent à chaque appel, comme les étiquettes d'un produit ou les lignes d'une note de frais. Même si tu déclares cinq paramètres, un appel finira par en demander un sixième, et ceux qui ne servent pas valent undefined à chaque fois.
Un paramètre du reste (une façon de recevoir les arguments restants regroupés dans un seul tableau ; c'est ce qui permet d'écrire des fonctions variadiques) s'écrit ...labels à la fin de la liste des paramètres. C'est le même ... qui regroupait les éléments restants lors de la déstructuration, sauf qu'ici il regroupe des arguments. Il ne peut être que le dernier paramètre : en placer un autre après lui provoque une SyntaxError.
// Écrire ...labels regroupe les arguments reçus dans un seul tableau
const buildTags = (...labels) => `Tags (${labels.length}) : ${labels.join(" / ")}`;
console.log(buildTags("Livraison gratuite", "En stock")); // Tags (2) : Livraison gratuite / En stock
console.log(buildTags("Nouveau")); // Tags (1) : Nouveau
// Dans l'autre sens, ... entre les parenthèses de l'appel transforme un tableau en arguments
console.log(buildTags(...["Nouveau", "Limité"])); // Tags (2) : Nouveau / Limité
// S'il y a aussi des paramètres nommés, place le paramètre du reste en dernier
const buildNotice = (orderId, ...notes) => `${orderId} (${notes.join(", ")})`;
console.log(buildNotice("A-1021", "Réfrigéré", "Créneau horaire")); // A-1021 (Réfrigéré, Créneau horaire)
console.log(buildNotice("A-1022")); // A-1022 ()
orderId, et les suivantes vont, dans l'ordre, dans les éléments de notes. Un paramètre du reste reçoit tout ce qui reste après les paramètres nommés.Un paramètre du reste ne peut pas avoir de valeur par défaut, mais quand aucun argument ne lui revient, notes est un tableau vide, et non undefined. Dans l'autre sens, si tu as un tableau et que tu veux passer ses éléments comme arguments séparés, écris ... entre les parenthèses de l'appel.
Transmettre des réglages par leur nom — objet options et déstructuration
Quand les réglages s'accumulent, comme pour l'envoi d'un e-mail, tu te retrouves avec des appels comme sendMail(to, subject, false, true). Impossible de savoir ce que signifient ce false et ce true sans ouvrir la définition de la fonction.
Avec le motif options (une façon de transmettre plusieurs réglages regroupés dans un seul objet), la fonction qui reçoit l'objet le déstructure et donne une valeur par défaut à chaque clé. Pour gérer les appels qui ne passent aucun réglage, ajoute = {} après le motif de déstructuration : un objet vide est alors utilisé quand aucun objet n'est transmis.
// Plus il y a de paramètres, plus il est difficile de savoir ce que transmet un appel
const sendMailOld = (to, subject, isUrgent, withPdf) =>
`${to} / ${subject} / ${isUrgent} / ${withPdf}`;
console.log(sendMailOld("alice@example.com", "Avis d'expédition", false, true));
// alice@example.com / Avis d'expédition / false / true
// Motif options : regroupe les réglages dans un objet et déstructure-le du côté qui le reçoit
const sendMail = (to, { subject = "Information", isUrgent = false } = {}) =>
`${to} / ${subject} / ${isUrgent}`;
console.log(sendMail("alice@example.com", { isUrgent: true })); // alice@example.com / Information / true
console.log(sendMail("alice@example.com")); // alice@example.com / Information / false
Au lieu de dépendre de l'ordre des paramètres, chaque valeur est identifiée par sa clé : les appels restent lisibles même quand les réglages se multiplient. Les clés correspondent par leur nom, donc même si tu les écris dans un autre ordre, comme dans { isUrgent: true, subject: "Renvoi" }, les valeurs reçues sont les mêmes.
Sans = {}, tu obtiens une TypeError
Si tu écris seulement le motif de déstructuration, comme dans { subject = "Information" }, un appel qui omet le deuxième argument lève TypeError: Cannot read properties of undefined (reading 'subject'). La raison : il essaie de lire une clé dans undefined, la valeur que contient le paramètre omis.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Que renvoie const countNotes = (id, ...notes) => notes.length; quand on l'appelle avec countNotes("A-1021") ?
Question 3Que renvoie const send = (to, { urgent = false } = {}) => urgent; quand on l'appelle avec send("alice@example.com") ?