En JavaScript, une structure clé-valeur devient vite indispensable dès qu’il faut retrouver, mettre à jour ou supprimer des données sans parcourir tout un tableau. La vraie question n’est pas seulement de stocker des paires, mais de choisir une structure qui reste lisible, sûre et cohérente avec le comportement du langage. Dans cet article, je passe en revue la table de hachage côté JavaScript, la place de `Map`, les cas où `Object` reste plus simple, et les pièges qui reviennent le plus souvent.
Ce qu’il faut retenir avant d’écrire un dictionnaire clé-valeur
- `Map` est la structure native la plus proche d’une table de hachage moderne en JavaScript.
- Les clés d’une `Map` peuvent être de n’importe quel type, et l’ordre d’itération suit l’insertion.
- `Object` reste pertinent pour des données JSON simples ou des schémas stables.
- `WeakMap` sert surtout à attacher des données à des objets sans bloquer leur collecte mémoire.
- Avec des clés objet, la comparaison se fait par référence, pas par contenu.
- Si vous devez sérialiser, anticipez la conversion avant d’écrire le code de production.
Ce que fait réellement une table de hachage en JavaScript
Une table de hachage associe une clé à une valeur pour retrouver l’information rapidement. En pratique, on attend quatre gestes simples: ajouter, lire, vérifier l’existence, supprimer. La spécification ECMAScript demande des temps d’accès en moyenne sublinéaires; selon le moteur, l’implémentation peut donc s’appuyer sur une table de hachage, un arbre ou une autre structure interne. Autrement dit, le détail bas niveau compte moins que le contrat que vous donne l’API. La documentation MDN rappelle aussi qu’une Map garde des clés uniques et une itération dans l’ordre d’insertion.
Cette nuance vaut la peine d’être gardée en tête, parce qu’elle explique pourquoi on ne choisit pas la structure au hasard. Quand la clé est dynamique et que l’ordre d’insertion a de la valeur, Map devient presque toujours le point de départ naturel.

Pourquoi Map est souvent le meilleur point de départ
Quand je veux un vrai dictionnaire en JavaScript, je prends Map presque sans hésiter. L’API est claire, l’ordre d’insertion est conservé, la taille se lit avec size, et les clés peuvent être de n’importe quel type, y compris des objets. La comparaison des clés suit SameValueZero: NaN est considéré comme égal à NaN, et deux références d’objets ne sont égales que si elles pointent vers le même objet.
| Critère | Map |
Object |
|---|---|---|
| Types de clés | N’importe quelle valeur | Chaînes et Symboles, avec coercition fréquente en usage dictionnaire |
| Itération | Ordre d’insertion | Règles d’énumération du langage, moins directes pour un dictionnaire |
| Taille | size |
Object.keys(...).length |
| Clés objet | Comparées par référence | Peu adapté comme dictionnaire d’objets sans transformation |
| Usage typique | Caches, index, compteurs, relations dynamiques | Configurations, JSON, structures fixes |
Si vous avez besoin d’une structure explicite, prévisible et facile à parcourir, Map fait très bien le travail. Et si vos données doivent vivre longtemps, le fait de ne pas dépendre du prototype d’un objet est un avantage concret, pas un détail théorique. Une fois ce choix posé, le vrai intérêt devient la mise en œuvre concrète.
Construire une hashmap simple avec Map
Créer, lire, vérifier, supprimer
Le cycle de base tient en quatre méthodes: set(), get(), has() et delete(). Je conseille de les garder en tête comme le vocabulaire naturel d’une table de hachage, parce qu’elles disent exactement ce que le code fait.
const stock = new Map();
stock.set("router", 14);
stock.set("firewall", 3);
console.log(stock.get("router")); // 14
console.log(stock.has("switch")); // false
stock.delete("firewall");
console.log(stock.size); // 1
Deux détails comptent ici. D’abord, set() retourne la map elle-même, ce qui permet l’enchaînement. Ensuite, get() renvoie undefined si la clé est absente, donc has() reste la méthode fiable quand undefined peut être une valeur légitime.
Lire aussi : GET vs POST - Le guide pour des requêtes HTTP parfaites
Compter des occurrences sans bricolage
Le cas d’usage le plus courant, à mon sens, reste le compteur. Tags, mots, événements, identifiants de session: dès qu’une clé peut revenir plusieurs fois, Map donne un code court et lisible.
function countWords(words) {
const counts = new Map();
for (const word of words) {
counts.set(word, (counts.get(word) ?? 0) + 1);
}
return counts;
}
const result = countWords(["api", "cache", "api", "map", "cache", "api"]);
for (const [word, count] of result) {
console.log(word, count);
}
Je trouve ce schéma particulièrement propre pour les statistiques, les labels ou les caches de calcul. Si vous devez ensuite repartir vers un objet simple, Object.fromEntries(result) transforme une liste de paires en objet, à condition que la forme cible corresponde bien à vos besoins de sérialisation.
Reste à savoir quand l’objet nu suffit encore, ce qui évite de surdimensionner votre structure.
Quand Object suffit encore
Je garde Object quand les clés sont connues à l’avance, que les données ressemblent à une configuration ou à un payload JSON, et que je n’ai pas besoin des clés non textuelles. Dans ce cas, la structure est simple, directe et très lisible pour toute l’équipe. Si je veux un dictionnaire pur à base de chaînes, je crée souvent un objet sans prototype avec Object.create(null) pour éviter les propriétés héritées.
const labels = Object.create(null);
labels.fr = "Français";
labels.en = "English";
console.log(Object.keys(labels)); // ["fr", "en"]
Ce choix est utile quand l’écosystème autour du code attend un objet classique, par exemple pour des échanges JSON ou des schémas de configuration. En revanche, si vous commencez à empiler des opérations de recherche, des suppressions et des clés dynamiques, je passe vite sur Map, parce que le code devient moins ambigu. La question suivante devient alors celle du cycle de vie des données, et c’est là que WeakMap change complètement de logique.
Le rôle discret de WeakMap dans les objets liés au cycle de vie
WeakMap n’est pas une version "allégée" de Map; c’est un outil différent, pensé pour des associations qui ne doivent pas retenir leurs clés en mémoire. Les clés doivent être des objets ou des symboles non enregistrés, et la collection n’est pas itérable. C’est idéal pour stocker des métadonnées sur des instances, des nœuds DOM ou des objets temporaires sans empêcher le garbage collector de faire son travail.
const metadata = new WeakMap();
function attach(node, info) {
metadata.set(node, info);
}
function read(node) {
return metadata.get(node);
}
Je l’utilise surtout quand la donnée appartient au cycle de vie de l’objet clé, pas quand elle doit être listée, exportée ou comptée. Dès qu’on a besoin d’un inventaire, d’une taille ou d’une boucle de parcours, WeakMap n’est plus le bon outil.
Les erreurs que je vois le plus souvent
- Utiliser
map["clé"]au lieu demap.get("clé"), puis croire que la donnée a disparu. - Tester
get()sanshas()alors queundefinedpeut être une valeur volontaire. - Créer un nouvel objet littéral pour relire une clé objet, alors qu’une
Mapcompare par référence. - Vouloir sérialiser une
Maptelle quelle dans du JSON sans conversion préalable. - Choisir
WeakMapalors qu’il faut itérer ou exposer les entrées. - Employer
Objectcomme dictionnaire sans penser au prototype, alors queObject.create(null)aurait suffi.
Il y a aussi un détail plus subtil: la comparaison de clés dans Map suit SameValueZero. Concrètement, NaN correspond à NaN, et les deux zéros ne sont pas distingués. C’est rarement bloquant, mais c’est le genre de nuance qui évite un diagnostic inutile en production. À partir de là, le bon réflexe consiste surtout à choisir la structure selon la durée de vie des données et la forme de vos clés.
Le réflexe que j’applique entre Map, Object et WeakMap
Mon choix tient en une règle simple. Map dès que je pense dictionnaire dynamique, compteur, cache ou relation clé-valeur avec itération fiable. Object dès que la structure est stable, JSON-friendly, et qu’elle ressemble davantage à un modèle de données qu’à un registre. WeakMap quand j’attache des informations à des objets sans vouloir bloquer leur collecte mémoire.
Si la structure devient centrale dans un chemin critique, je ne devine pas le comportement du moteur: je mesure sur des données réalistes. Dans un projet web, c’est souvent là que se joue la différence entre un code qui reste simple à maintenir et un code qui s’encombre de contournements inutiles. En pratique, quand je veux une vraie hashmap en JavaScript, je pars presque toujours de Map, puis je ne descends vers Object ou WeakMap que si le besoin est vraiment plus précis.