map() : transformer un tableau sans le modifier
Transformer un tableau avec map() sans toucher à l’original, distinguer map() de filter(), et arrondir correctement un montant calculé en JavaScript.
Où en êtes-vous avec cette notion ?
Une indication personnelle, enregistrée uniquement dans ce navigateur.
À lire ensuite
Le format café
L’essentiel à comprendre, le temps d’un café.
Envie de creuser ? Un cours plus complet vous attend juste après, à déplier sans quitter cette page.
Ce que vous allez comprendre
map() parcourt un tableau et en fabrique un nouveau, élément par élément. Le tableau de départ n’est pas modifié : c’est ce qui rend la méthode aussi sûre à utiliser.
Le principe
[1, 2, 3, 4]
↓ map(nombre => nombre * 2)
[2, 4, 6, 8]
// Node.js ou console du navigateur.
const nombres = [1, 2, 3, 4];
const doubles = nombres.map((nombre) => nombre * 2);
console.log(doubles); // [ 2, 4, 6, 8 ]
console.log(nombres); // [ 1, 2, 3, 4 ] : inchangé
La fonction passée à map() est appelée une fois par élément. Sa valeur de retour devient l’élément correspondant du nouveau tableau, qui garde la même longueur que l’original.
Un cas plus réaliste
const utilisateurs = [
{ id: 1, prenom: 'Alice', nom: 'Martin', actif: true },
{ id: 2, prenom: 'Bob', nom: 'Dupont', actif: false },
];
const noms = utilisateurs.map((user) => `${user.prenom} ${user.nom}`);
console.log(noms); // [ 'Alice Martin', 'Bob Dupont' ]
Chaque objet devient une chaîne. La forme de la donnée change ; le nombre d’éléments, non.
Transformer n’est pas sélectionner
map() transformer [1, 2, 3] → [2, 4, 6]
filter() sélectionner [1, 2, 3] → [2, 3]
Les deux se combinent, et se lisent dans l’ordre d’écriture :
const nomsActifs = utilisateurs
.filter((user) => user.actif)
.map((user) => user.nom);
console.log(nomsActifs); // [ 'Martin' ]
« Garde les utilisateurs actifs, puis récupère leur nom. » C’est aussi pourquoi map() est omniprésent dans les interfaces React : on y transforme couramment une liste de données en une liste d’éléments à afficher.
Fiche mémo
- Retourne un nouveau tableau, de même longueur.
- Ne modifie pas le tableau d’origine.
forEach()ne retourne rien : à réserver aux effets de bord.- Le résultat se range dans une variable et se réutilise ensuite.
L’idée à emporter : map() répond à « en quoi je transforme chaque élément ? », jamais à « lesquels je garde ? ».
Et si on allait plus loin ?
Le café vous a donné les repères. Prenez maintenant le temps de comprendre les mécanismes et de pratiquer, si vous le souhaitez.
Aller plus loinDu tableau transformé au montant juste à l’affichageDévelopper le coursReplier le cours
Ce que vous saurez faire
Ranger le résultat de map() dans une variable et le réutiliser, enchaîner filter() et map() pour une liste React, et arrondir un montant sans se faire piéger par les nombres à virgule. Les exemples se lisent avec Node.js ou dans la console du navigateur ; l’extrait React suppose un projet React déjà configuré.
1. Le tableau retourné est une donnée à part entière
C’est l’intérêt principal de map() : le nouveau tableau se range dans une variable et se réutilise autant de fois que nécessaire, pendant que l’original reste intact.
// Node.js ou console du navigateur.
const prixHT = [10, 20, 50];
const prixTTC = prixHT.map((prix) => prix * 1.2);
console.log(prixHT); // [ 10, 20, 50 ] : intact
console.log(prixTTC); // [ 12, 24, 60 ] : nouveau tableau
console.log(prixTTC[0]); // 12
const total = prixTTC.reduce((somme, prix) => somme + prix, 0);
console.log(total); // 96
prixHT ──► [10, 20, 50] (jamais touché)
│
│ map(prix => prix * 1.2)
▼
prixTTC ──► [12, 24, 60] (nouvelle référence)
Vous disposez maintenant de deux tableaux indépendants. Une nuance toutefois : map() crée un nouveau tableau, pas une copie profonde. Si les éléments sont des objets et que la fonction renvoie le même objet, les deux tableaux pointent vers les mêmes objets ; modifier l’un se verra dans l’autre.
Référence : Array.prototype.map().
2. Enchaîner filter() puis map(), et afficher une liste React
const utilisateurs = [
{ id: 1, nom: 'Martin', actif: true },
{ id: 2, nom: 'Dupont', actif: false },
{ id: 3, nom: 'Nguyen', actif: true },
];
const actifs = utilisateurs.filter((user) => user.actif).map((user) => user.nom);
console.log(actifs); // [ 'Martin', 'Nguyen' ]
L’ordre compte : filtrer d’abord réduit le nombre de transformations. Chaque maillon renvoie un nouveau tableau, donc utilisateurs n’est jamais modifié.
// Extrait de composant : à placer dans un projet React déjà configuré.
<ul>
{utilisateurs
.filter((user) => user.actif)
.map((user) => (
<li key={user.id}>{user.nom}</li>
))}
</ul>
Le résultat attendu est une liste de deux éléments. La propriété key doit être un identifiant stable de la donnée — ici user.id — et non l’index, qui change dès qu’on trie ou qu’on supprime un élément.
Référence : Array.prototype.filter().
3. Le piège des nombres à virgule
prix * 1.2 ne donne pas toujours un nombre « rond ». Les nombres JavaScript sont des flottants binaires : 1.2 et 0.1 n’ont pas de représentation exacte en base deux.
console.log(19.2 * 1.2); // 23.04
console.log(29.9 * 1.2); // 35.879999999999995
console.log(8.1 * 1.2); // 9.719999999999999
console.log(0.1 + 0.2); // 0.30000000000000004
Avec [10, 20, 50], le résultat tombe juste par chance. N’en tirez aucune règle générale : dès que les prix ont des centimes, des décimales parasites apparaissent.
Pour un affichage monétaire, arrondissez au moment de l’affichage, pas au milieu des calculs :
const arrondi = (valeur) => Math.round(valeur * 100) / 100;
console.log(arrondi(29.9 * 1.2)); // 35.88
console.log((29.9 * 1.2).toFixed(2)); // '35.88' : une chaîne, pas un nombre
const euros = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' });
console.log(euros.format(29.9 * 1.2)); // 35,88 € (espace insécable avant le symbole)
toFixed(2) renvoie une chaîne : c’est parfait pour afficher, jamais pour continuer à calculer. Pour une comptabilité réelle, la pratique la plus sûre reste de travailler en centimes entiers et de ne diviser qu’à l’affichage.
Référence : Number.prototype.toFixed().
Pièges et limites
- Passer une fonction toute faite sans réfléchir.
['1', '2', '3'].map(parseInt)renvoie[1, NaN, NaN]:map()transmet aussi l’index, queparseIntinterprète comme la base. Écrivez.map((n) => Number(n)). - Oublier le
return. Avec des accolades,.map((n) => { n * 2 })renvoie[undefined, undefined, …]. Sans accolades, le retour est implicite. - Utiliser
map()pour un effet de bord. Le tableau créé est alors jeté. PréférezforEach()ou une bouclefor…of. - Croire à une copie profonde.
objets.map((o) => o)produit un nouveau tableau contenant les mêmes objets. - Prendre l’index comme
keyReact. L’identité des éléments se casse au moindre tri ou suppression.
À vous de jouer
Vous recevez des prix hors taxes et une TVA de 20 % :
const prixHT = [10, 20, 50];
- Écrivez une seule ligne avec
map()qui produit[12, 24, 60], et rangez-la dansprixTTC. - Vérifiez que
prixHTest resté intact, puis calculez le total TTC. - Produisez un tableau de chaînes affichables, arrondies à deux décimales.
- Recommencez avec
[19.9, 29.9]et expliquez ce que vous observez.
Correction commentée
// Node.js ou console du navigateur.
const prixHT = [10, 20, 50];
const prixTTC = prixHT.map((prix) => prix * 1.2);
console.log(prixTTC); // [ 12, 24, 60 ]
console.log(prixHT); // [ 10, 20, 50 ]
const total = prixTTC.reduce((somme, prix) => somme + prix, 0);
console.log(total); // 96
const affichage = prixTTC.map((prix) => prix.toFixed(2));
console.log(affichage); // [ '12.00', '24.00', '60.00' ]
La ligne demandée est prixHT.map((prix) => prix * 1.2). Ajouter 20 % revient à multiplier par 1.2 ; la fonction fléchée à corps unique renvoie l’expression sans return. Le résultat est un nouveau tableau : c’est pour cela que prixHT s’affiche inchangé juste après, et que prixTTC peut servir plusieurs fois — une fois pour le total, une fois pour l’affichage.
Le point 4 est celui qui surprend :
console.log([19.9, 29.9].map((prix) => prix * 1.2));
// [ 23.88, 35.879999999999995 ]
19.9 * 1.2 tombe juste à l’affichage, 29.9 * 1.2 non. Ce n’est pas un bug de map() : c’est l’arithmétique flottante. La correction consiste à arrondir uniquement pour présenter la valeur :
const arrondi = (valeur) => Math.round(valeur * 100) / 100;
console.log([19.9, 29.9].map((prix) => arrondi(prix * 1.2)));
// [ 23.88, 35.88 ]
console.log([19.9, 29.9].map((prix) => (prix * 1.2).toFixed(2)));
// [ '23.88', '35.88' ]
Math.round(valeur * 100) / 100 conserve un nombre, utilisable dans un calcul ultérieur. toFixed(2) conserve toujours deux décimales mais renvoie une chaîne, donc uniquement pour l’affichage. Choisissez selon ce que vous ferez ensuite de la valeur.
Vous pouvez aussi vous arrêter ici. L’approfondissement est facultatif.
Les repères Cours Café
Pour aller à la source
Documentation de référence. Vérification éditoriale encore à effectuer.
Gardez une trace de cette idée.
Favoris, notes et progression seront disponibles après connexion du stockage distant.