Comment utiliser Set en JavaScript ? Guide et exemples

Dans cet article

  • Un Set est une collection de valeurs uniques introduite avec ES6 en 2015
  • La méthode add() insère un élément, tandis que has() vérifie sa présence en O(1)
  • Dédupliquer un tableau se fait en une seule ligne grâce à [...new Set(array)]
  • Depuis 2024, les méthodes ensemblistes (union, intersection, difference) sont supportées nativement dans tous les navigateurs modernes
  • Un Set est jusqu’à 10 fois plus rapide qu’un Array pour vérifier l’existence d’un élément sur de gros volumes
  • La propriété size remplace length et retourne le nombre d’éléments sans doublon

Quand j’ai découvert l’objet Set en JavaScript, je me suis demandé pourquoi je n’avais pas utilisé cette structure plus tôt. Après des années à écrire des boucles indexOf ou des filtres manuels pour éliminer les doublons dans mes tableaux, le Set m’a fait gagner un temps considérable. Si vous travaillez régulièrement avec des collections de données en JS, cette structure native va transformer votre façon de coder. Dans ce guide, je vous montre comment l’utiliser concrètement, avec des exemples issus de mes projets réels.

Qu’est-ce qu’un Set en JavaScript ?

Un javascript set est une structure de données introduite avec ECMAScript 2015 (ES6) qui stocke des valeurs uniques de n’importe quel type. Contrairement à un tableau classique, un Set refuse automatiquement les doublons. Si vous tentez d’ajouter une valeur déjà présente, elle est simplement ignorée sans lever d’erreur.

Pour bien comprendre, pensez à un Set comme un ensemble mathématique : chaque élément n’apparaît qu’une seule fois. Cette propriété rend le Set particulièrement utile pour la déduplication, les recherches rapides et les opérations ensemblistes.

Voici les caractéristiques fondamentales :

  • Les valeurs sont ordonnées par insertion (l’ordre est préservé)
  • L’unicité repose sur l’algorithme SameValueZero (similaire à ===, sauf que NaN === NaN est considéré vrai)
  • Un Set accepte tous les types : primitifs, objets, fonctions
  • La vérification d’existence se fait en temps constant O(1)

Si vous débutez en JavaScript, je vous recommande de consulter mon guide sur les étapes pour apprendre JavaScript avant de vous lancer dans les structures avancées.

Le constructeur new Set() accepte un itérable comme un tableau pour initialiser la collection
Le constructeur new Set() accepte un itérable comme un tableau pour initialiser la collection

Créer et initialiser un Set

La création d’un Set passe par le constructeur new Set(). Vous pouvez l’initialiser vide ou lui passer un itérable (tableau, chaîne de caractères, autre Set).

Set vide

const monSet = new Set();
console.log(monSet.size); // 0

Set initialisé avec un tableau

const fruits = new Set(['pomme', 'banane', 'cerise', 'pomme']);
console.log(fruits.size); // 3 (le doublon 'pomme' est ignoré)
console.log(fruits); // Set {'pomme', 'banane', 'cerise'}

Set initialisé avec une chaîne

const lettres = new Set('javascript');
console.log(lettres); // Set {'j', 'a', 'v', 's', 'c', 'r', 'i', 'p', 't'}
console.log(lettres.size); // 9 (le 'a' en double est supprimé)

Je précise un point important : le constructeur Set() attend un itérable en argument, pas une liste d’arguments. Si vous écrivez new Set(1, 2, 3), seul le premier élément sera pris en compte. Utilisez toujours un tableau : new Set([1, 2, 3]).

Notez que la propriété size (et non length) retourne le nombre d’éléments. C’est une différence notable avec les tableaux. Pour en savoir plus sur la taille des tableaux, consultez mon article sur la taille des tableaux en JavaScript.

Méthodes principales du Set

L’objet Set expose une API concise mais puissante. Voici les méthodes que j’utilise quotidiennement dans mes projets Symfony et WordPress.

add() : ajouter un élément

const tags = new Set();
tags.add('php');
tags.add('javascript');
tags.add('symfony');
tags.add('javascript'); // ignoré, déjà présent
console.log(tags.size); // 3

La méthode add() retourne le Set lui-même, ce qui permet le chaînage :

const stack = new Set();
stack.add('react').add('vue').add('angular');
console.log(stack.size); // 3

has() : vérifier l’existence

const permissions = new Set(['read', 'write', 'admin']);
console.log(permissions.has('admin')); // true
console.log(permissions.has('delete')); // false

C’est la méthode la plus performante du Set. Sur un tableau de 100 000 éléments, has() est en moyenne 10 fois plus rapide qu’un Array.includes() car la recherche se fait en O(1) au lieu de O(n).

delete() : supprimer un élément

const langages = new Set(['python', 'ruby', 'php']);
langages.delete('ruby');
console.log(langages); // Set {'python', 'php'}
console.log(langages.delete('java')); // false (élément absent)

clear() : vider le Set

const cache = new Set([1, 2, 3]);
cache.clear();
console.log(cache.size); // 0

Méthode Description Retour Complexité
add(valeur) Ajoute un élément au Set Le Set (chaînable) O(1)
has(valeur) Vérifie si la valeur existe true / false O(1)
delete(valeur) Supprime un élément true / false O(1)
clear() Vide entièrement le Set undefined O(n)
size Nombre d’éléments (propriété) Entier O(1)
forEach(cb) Itère sur chaque élément undefined O(n)
values() Retourne un itérateur Iterator O(1)

Parcourir un Set avec forEach et for…of

Un Set est un objet itérable. Vous disposez de plusieurs méthodes pour parcourir ses éléments.

forEach()

const technologies = new Set(['Node.js', 'Deno', 'Bun']);

technologies.forEach((valeur) => {
  console.log(valeur);
});
// Node.js
// Deno
// Bun

Particularité : le callback de forEach sur un Set reçoit la valeur deux fois en arguments (valeur, valeur, set). C’est pour rester cohérent avec l’API de Map.forEach() qui passe (valeur, clé, map). Dans un Set, clé et valeur sont identiques.

for…of

const couleurs = new Set(['rouge', 'vert', 'bleu']);

for (const couleur of couleurs) {
  console.log(couleur);
}

C’est la syntaxe que je préfère au quotidien : plus lisible et compatible avec break et continue, ce que forEach ne permet pas.

Conversion en tableau

Quand j’ai besoin des méthodes de tableau (map, filter, reduce), je convertis le Set en Array :

const nombres = new Set([10, 20, 30, 40]);
const doubles = [...nombres].map(n => n * 2);
console.log(doubles); // [20, 40, 60, 80]

L’opérateur spread [...] et Array.from() font le même travail. J’utilise le spread par habitude car il est plus concis.

Les opérations ensemblistes comme union et intersection sont désormais natives en JavaScript
Les opérations ensemblistes comme union et intersection sont désormais natives en JavaScript

Cas pratiques et exemples concrets

Voici les situations où j’utilise systématiquement un javascript set dans mes projets.

Dédupliquer un tableau en une ligne

C’est de loin le cas d’usage le plus courant. Avant ES6, il fallait écrire une boucle ou un filter avec indexOf. Maintenant :

const brut = [1, 2, 3, 2, 1, 4, 5, 3];
const unique = [...new Set(brut)];
console.log(unique); // [1, 2, 3, 4, 5]

J’utilise cette technique dans pratiquement tous mes projets WordPress quand je récupère des identifiants de catégories ou de tags qui peuvent contenir des doublons après une requête WP_Query.

Suivre les éléments déjà traités

const traites = new Set();

function traiterCommande(id) {
  if (traites.has(id)) {
    console.log(`Commande ${id} déjà traitée`);
    return;
  }
  traites.add(id);
  // logique de traitement
  console.log(`Commande ${id} en cours de traitement`);
}

traiterCommande(101); // en cours de traitement
traiterCommande(102); // en cours de traitement
traiterCommande(101); // déjà traitée

Gérer les connexions WebSocket uniques

const connexions = new Set();

function onConnect(socket) {
  connexions.add(socket);
  console.log(`${connexions.size} utilisateur(s) connecté(s)`);
}

function onDisconnect(socket) {
  connexions.delete(socket);
}

function broadcast(message) {
  connexions.forEach(socket => socket.send(message));
}

C’est un pattern que j’utilise régulièrement sur des projets Node.js. Le Set garantit qu’un même socket ne sera jamais compté deux fois, même en cas de reconnexion rapide.

Compter les valeurs uniques

const visiteurs = ['alice', 'bob', 'alice', 'charlie', 'bob', 'alice'];
const nbUniques = new Set(visiteurs).size;
console.log(`${nbUniques} visiteurs uniques`); // 3 visiteurs uniques

Si vous travaillez avec des objets JavaScript, gardez à l’esprit que le Set compare les objets par référence, pas par valeur. Deux objets avec les mêmes propriétés seront considérés comme différents.

Opérations ensemblistes : union, intersection, difference

Depuis 2024, les navigateurs modernes supportent nativement les méthodes ensemblistes du Set. C’est une avancée majeure : avant, il fallait tout coder manuellement.

union() : combiner deux ensembles

const frontend = new Set(['react', 'vue', 'angular']);
const backend = new Set(['node', 'express', 'vue']);

const tous = frontend.union(backend);
console.log(tous); // Set {'react', 'vue', 'angular', 'node', 'express'}

intersection() : éléments communs

const communs = frontend.intersection(backend);
console.log(communs); // Set {'vue'}

difference() : éléments exclusifs

const exclusifFrontend = frontend.difference(backend);
console.log(exclusifFrontend); // Set {'react', 'angular'}

symmetricDifference() : éléments non partagés

const symetrique = frontend.symmetricDifference(backend);
console.log(symetrique); // Set {'react', 'angular', 'node', 'express'}

Cette méthode retourne tous les éléments qui sont dans l’un ou l’autre des ensembles, mais pas dans les deux. C’est l’équivalent de la différence symétrique en mathématiques.

isSubsetOf(), isSupersetOf(), isDisjointFrom()

const js = new Set(['javascript']);
const langages = new Set(['javascript', 'python', 'php']);

console.log(js.isSubsetOf(langages));     // true
console.log(langages.isSupersetOf(js));   // true
console.log(js.isDisjointFrom(langages)); // false

Pour les navigateurs plus anciens ou Node.js en version antérieure à 22, voici la version manuelle avec le spread operator :

// Union manuelle (compatible ES6+)
const unionManuelle = new Set([...frontend, ...backend]);

// Intersection manuelle
const interManuelle = new Set([...frontend].filter(x => backend.has(x)));

// Différence manuelle
const diffManuelle = new Set([...frontend].filter(x => !backend.has(x)));
Comparer Set et Array permet de choisir la structure la plus adaptée à chaque situation
Comparer Set et Array permet de choisir la structure la plus adaptée à chaque situation

Set vs Array : comparatif et performances

La question revient souvent dans mes formations : quand utiliser un Set plutôt qu’un Array ? Voici un comparatif basé sur mes benchmarks et mon expérience terrain.

Critère Set Array
Vérification d’existence O(1) avec has() O(n) avec includes()
Ajout d’un élément O(1) avec add() O(1) avec push()
Suppression par valeur O(1) avec delete() O(n) avec splice()
Accès par index Non supporté O(1)
Doublons Impossibles Autorisés
Méthodes de transformation Limitées (pas de map, filter) Très riches
Sérialisation JSON Nécessite conversion Native
Taille mémoire (10k éléments) Comparable Comparable

Ma règle simple : si l’unicité est importante ou si vous faites beaucoup de vérifications d’existence, choisissez un Set. Si vous avez besoin d’accéder aux éléments par index, de les trier, ou de les transformer avec map/filter/reduce, restez sur un Array.

En pratique, je combine souvent les deux. Je traite les données avec un Set pour la déduplication, puis je convertis en Array quand j’ai besoin de manipuler le résultat. Vous retrouverez cette approche dans beaucoup de projets JavaScript modernes, notamment avec les frameworks comme React ou Vue.

Pour comprendre les mécanismes asynchrones qui accompagnent souvent ces traitements, jetez un œil à mon article sur le sleep en JavaScript et la gestion des délais.

WeakSet et cas avancés

JavaScript propose aussi un WeakSet, une variante du Set avec des caractéristiques très spécifiques :

  • Il n’accepte que des objets (pas de primitifs)
  • Les références sont faibles : si l’objet n’est plus référencé ailleurs, il est automatiquement supprimé par le garbage collector
  • Il n’est pas itérable (pas de forEach, pas de size)
const weakSet = new WeakSet();

let utilisateur = { nom: 'Thomas' };
weakSet.add(utilisateur);
console.log(weakSet.has(utilisateur)); // true

utilisateur = null; // l'objet sera collecté par le GC
// weakSet ne le retiendra plus

J’utilise le WeakSet dans deux cas précis :

1. Marquer des éléments DOM déjà initialisés :

const initialises = new WeakSet();

function initComposant(element) {
  if (initialises.has(element)) return;
  initialises.add(element);
  // initialisation du composant
  element.addEventListener('click', handleClick);
}

Quand l’élément DOM est supprimé de la page, le WeakSet libère automatiquement la mémoire. Avec un Set classique, il faudrait penser à appeler delete() manuellement pour éviter les fuites mémoire.

2. Vérifier l’authenticité d’un objet :

const objetsValides = new WeakSet();

class Commande {
  constructor(montant) {
    this.montant = montant;
    objetsValides.add(this);
  }

  static estValide(obj) {
    return objetsValides.has(obj);
  }
}

const cmd = new Commande(150);
console.log(Commande.estValide(cmd)); // true
console.log(Commande.estValide({ montant: 150 })); // false

Ce pattern garantit que seuls les objets créés via le constructeur sont considérés comme valides, même si un objet externe a la même structure. C’est une technique de branding très utilisée dans les bibliothèques JavaScript professionnelles.

Erreurs courantes et bonnes pratiques

Après plus de 10 ans de développement JavaScript, voici les pièges que je vois le plus souvent avec le Set.

Piège n°1 : les objets ne sont pas dédupliqués par valeur

const set = new Set();
set.add({ id: 1 });
set.add({ id: 1 });
console.log(set.size); // 2 ! Les deux objets sont différents en mémoire

Pour dédupliquer des objets par propriété, utilisez une Map ou sérialisez la clé :

const utilisateurs = [
  { id: 1, nom: 'Alice' },
  { id: 2, nom: 'Bob' },
  { id: 1, nom: 'Alice' }
];

const ids = new Set();
const uniques = utilisateurs.filter(u => {
  if (ids.has(u.id)) return false;
  ids.add(u.id);
  return true;
});
console.log(uniques.length); // 2

Piège n°2 : oublier que Set n’est pas sérialisable en JSON

const monSet = new Set([1, 2, 3]);
console.log(JSON.stringify(monSet)); // {} (objet vide !)

// Solution : convertir en Array avant
console.log(JSON.stringify([...monSet])); // [1,2,3]

C’est un piège classique quand on envoie des données à une API REST. Pensez toujours à convertir vos Sets en tableaux avant la sérialisation.

Piège n°3 : confondre Set et l’accesseur set

En JavaScript, le mot set désigne aussi un accesseur (setter) dans les classes et objets. Ce sont deux concepts totalement différents :

// Ceci est un ACCESSEUR set (setter)
const personne = {
  _nom: '',
  set nom(valeur) {
    this._nom = valeur.trim();
  }
};

// Ceci est un objet SET (collection)
const ensemble = new Set(['a', 'b', 'c']);

Bonnes pratiques

  • Utilisez const pour déclarer vos Sets : le contenu peut changer, mais la référence doit rester stable
  • Préférez has() à la conversion en Array suivie de includes()
  • Pour les notifications et alertes, un Set de messages déjà affichés évite les doublons visuels. Découvrez aussi comment gérer les alertes en JavaScript
  • Pensez au WeakSet pour les références DOM temporaires afin d’éviter les fuites mémoire
  • Quand vous travaillez avec des timers et des intervalles, un Set peut servir à stocker les identifiants d’intervalles actifs. Consultez mon guide sur setInterval en JavaScript pour combiner ces approches

Pour approfondir vos compétences, je vous conseille de consulter la spécification officielle ECMAScript sur les objets Set qui détaille le fonctionnement interne de cette structure.

À retenir

  • Utilisez [...new Set(array)] pour dédupliquer un tableau en une seule ligne
  • Privilégiez has() plutôt que Array.includes() dès que votre collection dépasse 100 éléments
  • Les méthodes union(), intersection(), difference() sont désormais natives : vérifiez la compatibilité navigateur avant de les utiliser en production
  • Convertissez toujours un Set en Array avec [...monSet] avant de le sérialiser en JSON
  • Choisissez WeakSet pour les références DOM temporaires afin d’éviter les fuites mémoire

Questions fréquentes


C’est quoi un Set en JavaScript ?

Un Set est une collection de valeurs uniques introduite avec ES6 en 2015. Il stocke des éléments de n’importe quel type (nombres, chaînes, objets) et refuse automatiquement les doublons. Contrairement à un tableau, un Set ne permet pas l’accès par index mais offre des performances supérieures pour la vérification d’existence grâce à sa complexité en O(1).


Comment initialiser un Set en JavaScript ?

Vous pouvez créer un Set vide avec new Set() ou l’initialiser avec un itérable comme un tableau : new Set(['a', 'b', 'c']). Les doublons sont automatiquement supprimés lors de l’initialisation. Attention : passez un tableau, pas des arguments séparés. new Set(1, 2, 3) ne fonctionne pas comme attendu.


Quelle est la complexité temporelle des méthodes du Set en JavaScript ?

Les méthodes add(), has() et delete() s’exécutent en O(1) (temps constant), quelle que soit la taille du Set. C’est un avantage majeur par rapport aux tableaux où includes() est en O(n). Seule la méthode clear() et les itérations (forEach) sont en O(n).


Comment convertir un Set en Array en JavaScript ?

Deux méthodes existent : l’opérateur spread [...monSet] ou la fonction Array.from(monSet). Les deux produisent le même résultat. Cette conversion est nécessaire pour utiliser les méthodes de tableau comme map(), filter() ou pour sérialiser en JSON avec JSON.stringify().


Quelle différence entre Set et WeakSet en JavaScript ?

Le WeakSet n’accepte que des objets (pas de primitifs), ses références sont faibles (le garbage collector peut supprimer les objets non référencés ailleurs), et il n’est pas itérable (pas de forEach, pas de propriété size). Utilisez-le pour marquer des éléments DOM ou valider l’authenticité d’objets sans risquer de fuites mémoire.


Comment faire une union ou intersection de deux Sets ?

Depuis 2024, les navigateurs modernes supportent les méthodes natives : setA.union(setB), setA.intersection(setB), setA.difference(setB) et setA.symmetricDifference(setB). Pour les environnements plus anciens, utilisez le spread operator : new Set([...setA, ...setB]) pour l’union, ou new Set([...setA].filter(x => setB.has(x))) pour l’intersection.


Damien Roux
Damien Roux

Ingénieur système et expert hébergement web. Fondateur de web-city.fr, il partage guides pratiques, comparatifs objectifs et outils gratuits pour choisir le bon hébergeur et créer son site WordPress.

Scroll to Top