Beaucoup d’avancées ont été faites avec ES6 mais prenons un petit moment pour examiner deux nouveaux constructeurs qui ont été introduits dans la spécification javascript ES6 j’ai nommé Set() et Map()

  1. Set : L’objet Set vous permet de stocker des valeurs uniques de tout type.
  2. Map : L’objet Map vous permet de stocker les paires clé-valeur et de mémoriser l’ordre d’insertion original des clés.

L’objectif de ces nouveaux constructeurs est de fournir des moyens plus faciles et plus efficaces de structurer et d’accéder aux données dans certains cas d’utilisation. Pour faire suite à mon article sur les méthodes de tableau javascript, nous examinerons ici le fonctionnement des ensembles (sets) et des maps et explorerons certaines des opérations qui peuvent être effectuées sur eux.

L’objet Set en javascript ES6

La documentation MDN décrit l’objet Set comme suit :

Les objets Set sont des ensembles de valeurs. Il est possible d’itérer sur les éléments contenus dans l’objet Set dans leur ordre d’insertion. Une valeur donnée ne peut apparaître qu’une seule fois par Set.

L’objet JavaScript Set se comporte de la même manière que l’objet mathématique Set. Il permet l’ajout de valeurs distinctes et fournit des méthodes utiles sur son prototype. Ces méthodes comprennent l’ajout, la suppression et l’itération des éléments présents dans l’ensemble.

Comparaison des objets javascript Array et Set

Un tableau, comme un ensemble, est une structure de données qui permet d’ajouter, de supprimer et de boucler des opérations sur ses éléments. Cependant, un tableau diffère d’un ensemble en ce sens qu’il permet l’addition de valeurs dupliquées et que ses opérations sont relativement plus lentes.

La recherche dans un tableau a une complexité temporelle linéaire de O(n), la même chose que l’insertion d’un élément au milieu d’un tableau. Cela signifie que le temps d’exécution de la recherche et de l’insertion d’éléments dans un tableau augmente à mesure que la taille du tableau augmente.

Les méthodes de tableau JavaScript Push et Pop ont un temps d’exécution de O(1) ce qui signifie que ces opérations auront un temps d’exécution constant quelle que soit la taille du tableau. Cependant, dans la pratique, l’opération Push est O(n) car les coûts de copie sont encourus lorsque de nouveaux emplacements de mémoire contigus sont alloués au réseau nouvellement formé.

En revanche, toutes les opérations d’insertion, de suppression et de recherche de Sets ont une durée de fonctionnement de seulement O(1).

Comment créer un ensemble (Set) en javascript ?

Créons un ensemble :

const set = new Set();

console.log(set); // Set {}

Comment initialiser un ensemble (Set) en javascript ?

Pour initialiser un ensemble, on peut passer un tableau de valeurs au constructeur de l’ensemble, cela va créer un ensemble avec ces valeurs :

const confectioneries = new Set(['oreo', 'marshmallow','oreo', 'kitkat', 'gingerbread']);

console.log(confectioneries); // result: Set { 'oreo', 'marshmallow', 'kitkat', 'gingerbread' }

Dans l’extrait ci-dessus, la valeur en double “oreo” est discrètement supprimée de l’ensemble et seules les valeurs uniques sont renvoyées.

Comment ajouter un élément dans un ensemble (Set) javascript ?

Nous pouvons ajouter plus d’éléments à un ensemble en utilisant la méthode add(). Cette méthode ajoute une nouvelle valeur à l’objet Set et retourne le Set. Une tentative d’ajout d’un élément dupliqué à l’objet Set ne retournerait pas d’erreur, au lieu de cela, l’élément ne sera pas ajouté.

Prenons un exemple :

const confectioneries = new Set(['oreo', 'marshmallow', 'kitkat', 'oreo','gingerbread']);

confectioneries.add('donut');

console.log(confectioneries); //_ log result: Set { 'oreo', 'marshmallow', 'kitkat', 'gingerbread', 'donut' } _

confectioneries.add('kitkat');

console.log(confectioneries); //_ log result: Set { 'oreo', 'marshmallow', 'kitkat', 'gingerbread', 'donut' } _

Comment supprimer un élément dans un ensemble (Set) javascript ?

Avec les ensembles, nous pouvons supprimer des éléments en utilisant l’une ou l’autre de ces commandes :

  • delete()
  • clear()

Pour utiliser la méthode delete(), la valeur à supprimer est transmise à la méthode. La méthode retournera une valeur booléenne vraie si la suppression a réussi et fausse si ce n’est pas le cas. Nous pouvons supprimer tous les éléments de l’objet Set en utilisant la méthode clear().

Essayons les deux méthodes dans cet exemple :

confectioneries.delete('kitkat');

console.log(confectioneries); //_ log result: Set { 'oreo', 'marshmallow', 'gingerbread', 'donut' }_

confectioneries.clear();

console.log(confectioneries); // log result: Set {}

Comment connaitre la taille d’un ensemble (Set) en javascript ?

Nous pouvons obtenir la taille d’un ensemble en utilisant la propriété size sur le prototype de l’ensemble. Ceci est similaire à la propriété length pour les tableaux :

const confectioneries = new Set(['oreo', 'marshmallow', 'kitkat', 'oreo','gingerbread']);

console.log(confectioneries.size); // log result: 5

Comment rechercher un élément parmi un ensemble (Set) javascript ?

Il se peut que nous ayons besoin de savoir si un ensemble contient un élément particulier. Ceci peut être réalisé en utilisant la méthode has(). La méthode has() retourne true si l’élément est dans l’objet Set, et false s’il ne l’est pas :

const confectioneries = new Set(['oreo', 'marshmallow', 'kitkat', 'oreo','gingerbread']);

console.log(confectioneries.has('marshmallow')); // log result: true

Comment recupérer les éléments d’un ensemble (Set) javascript ?

Nous pouvons retourner les éléments d’un objet Set dans le même ordre d’insertion en utilisant la méthode values(). Cette méthode retourne un nouvel objet setIterator . Une méthode similaire pour retourner les éléments d’un ensemble est la méthode keys() :

const confectioneries = new Set(['oreo', 'marshmallow', 'kitkat', 'oreo','gingerbread', 'donut']);

console.log(confectioneries.values()); // _log result: _[_Set Iterator] { 'oreo', 'marshmallow', 'kitkat', 'gingerbread', 'donut' }_

console.log(confectioneries.keys()); //_ log result: _[_Set Iterator] { 'oreo', 'marshmallow', 'kitkat', 'gingerbread', 'donut' }_

L’objet setIterator est un objet Iterator car il implémente les protocoles Iteratable et Iterator. Le protocole Iterable spécifie un moyen d’itération à travers un ensemble de valeurs en utilisant des constructions en boucle. Il permet également d’itérer les valeurs à l’aide de la méthode next(). Quand nous appelons next() sur un objet setIterator, nous obtenons la valeur suivante dans l’itération et une false si toutes les valeurs du Set ont été itérées :

const confectioneries = new Set(['oreo', 'marshmallow', 'kitkat', 'oreo','gingerbread', 'donut']);

let iterator = confectioneries.values();

console.log( iterator.next()); // _{ value: 'oreo', done: false } 
_
console.log( iterator.next()); // _{ value: 'marshmallow', done: false }
_
console.log( iterator.next()); //_ { value: 'kitkat', done: false }
_
console.log( iterator.next()); //_ { value: 'gingerbread', done: false }
_
console.log( iterator.next()); //_ { value: 'donut', done: false }
_
console.log( iterator.next()); // _{ value: undefined, done: true }_

Puisque les ensembles implémentent le protocole Itérable, les constructions de boucle telles que for…of peuvent être utilisées comme indiqué ci-dessous :

for (let confectionery of confectioneries) {
  console.log(confectionery);
}

/_ _console.log() result 
oreo
marshmallow
kitkat
gingerbread
donut 
__/

L’objet WeakSet en javascript

Les WeakSets offrent une flexibilité supplémentaire lors de l’utilisation de la structure de données Set. Ils sont différents des Sets réguliers en ce sens qu’ils n’acceptent que les objets et ne sont pas itérables ; ils ne peuvent pas être bouclés, et n’ont pas de méthode clear(). Comment, alors, apportent-ils une flexibilité supplémentaire ? Je vais vous dire ça dans un instant.

Nous pouvons créer un objet WeakSet en utilisant le constructeur WeakSet :

let user1 = {name: 'user 1', email: 'user1@example.com'};
let user2 = {name: 'user 2', email: 'user2@example.com'};
let user3 = {name: 'user 3', email: 'user3@example.com'};

const users = new WeakSet([user1, user2, user3]);

Le code ci-dessus crée un nouvel objet WeakSet, ajoutant des éléments autres que des objets renvoie un TypeError :

users.add('user 4');

console.log(users); // TypeError: Invalid value used in weak set

Comme les WeakSets n’ont pas de méthode clear(), les objets ne peuvent être supprimés qu’en les mettant à null. Cela fonctionne parce que les algorithmes du ramasse-miette de JavaScript libéreront automatiquement la mémoire allouée à l’objet nul, le supprimant ainsi du WeakSet.

C’est merveilleux parce que les objets WeakSets réglés sur null sont ramassés à la poubelle pendant que le programme est encore en cours d’exécution, ce qui réduit la consommation de mémoire et empêche les fuites, surtout lorsqu’il s’agit d’énormes quantités de données générées de façon asynchrone.

Cette fonction vous permet d’écrire des solutions légères aux problèmes de programmation sans avoir à vous soucier des détails de la gestion de la mémoire.

L’objet Map en javascript ES6

Les Maps Javascript sont des objets conçus pour stocker et récupérer efficacement des éléments en fonction d’une clé unique pour chaque élément. Une Map stocke des paires clé-valeur où les clés et les valeurs peuvent être soit des valeurs primitives, soit des objets, soit les deux.

La documentation de MDN décrit l’objet Map comme suit :

Un objet Map permet de retrouver ses éléments dans leur ordre d’insertion. Par exemple, une boucle for...of renverra un tableau de [clé, valeur] pour chaque itération.

Comment créer une Map en javascript ?

Comme les Sets, les Maps sont faciles à créer. Créez une Map à l’aide du constructeur Map :

const users = new Map();

console.log(users); // Map {}

Comment ajouter un élément dans Map javascript ?

Les paires clé-valeur sont ajoutées à une Map à l’aide de la méthode set(). Cette méthode prend en compte deux arguments, le premier étant la clé et le second, la valeur, qui est référencée par la clé :

users.set('John Doe', {
  email: 'johndoe@example.com',
});

users.set('Jane Doe', {
  email: 'janedoe@example.com',
});

console.log(users);

/__ console.log result 
Map {
  'John Doe' => { email: 'johndoe@example.com'},
  'Jane Doe' => { email: 'janedoe@example.com'} }
__/

Contrairement aux Sets qui suppriment les clés dupliquées, Maps met à jour la valeur attachée à cette clé :

users.set('John Doe', {
  email: 'johndoe477@example.com',
});

console.log(users);

/__ console.log result 
Map {
  'John Doe' => {email: 'johndoe477@example.com'},
  'Jane Doe' => { email: 'janedoe@example.com'} }
__/

Lorsque vous exécutez l’exemple ci-dessus, le courriel de John DoeUntel sera remplacé proprement. Cool 🙂

Comment supprimer un élément dans Map javascript ?

Comme pour les ensembles, les combinaisons clé-valeur peuvent être supprimées à l’aide de la méthode delete(). La clé à effacer est transmise à la méthode delete() comme indiqué ci-dessous :

users.delete('Jane Doe');

Les Maps ont aussi une méthode clear(), qui supprime toutes les paires clé-valeur de l’objet Map :

users.clear();

console.log(users); // Map {}

Comment rechercher un élément parmi une Map javascript ?

Les Maps ont aussi une méthode has() qui vérifie si une clé existe dans une Map. Cette méthode retournera true si la clé est dans la Map et false si elle ne l’est pas :

let users = new Map();

users.set('John Doe', {
  email: 'johndoe@example.com',
});

users.set('Jane Doe', {
  email: 'janedoe@example.com',
});

console.log(users.has('John Doe')); // true

Comment récupérer les éléments d’une Map javascript ?

La valeur d’une clé dans un objet Map peut être obtenue en utilisant la méthode get sur le prototype Map :

console.log(users.get('Jane Doe'); // { email: 'janedoe@example.com' }

Il est possible d’obtenir toutes les clés et valeurs d’un objet Map en utilisant les méthodes keys() et values() respectivement. Ces deux méthodes retournent un nouvel objet MapIterator qui a une méthode next() utilisable pour boucler les éléments de la Map :

let userKeys = users.keys();

console.log(userKeys.next()); // { value: 'John Doe', done: false }

let userValues = users.values();

console.log(userValues.next()); // _{ value: { email: 'johndoe@example.com' }

Comme pour les Sets, les boucles telles que for…of et forEach() peuvent être utilisées pour itérer à travers les éléments de la Map :

for (let user of users) {
  console.log('[for...of]: ', user);
}

/_ Log result
  _[_for...of]:  _[_ 'John Doe', { email: 'johndoe@example.com' } ]
  _[_for...of]:  _[___ 'Jane Doe', { email: 'janedoe@example.com' } ]
_/

users.forEach((value, key) => console.log('[__forEach()]:  ', key, value));

/*_ Log result
  [__forEach()]:   John Doe { email: 'johndoe@example.com' }
  _[_forEach()]:   Jane Doe { email: 'janedoe@example.com' }
*_/

L’objet WeakMap en javascript

Comme pour les WeakSets, les WeakMaps diffèrent des objets Maps normaux. Les WeakMaps n’acceptent que les objets comme clés, ne sont pas itérables et n’ont pas de méthode clear().

Un constructeur WeakMap est utilisé pour créer un objet WeakMap.

Prenons un exemple :

let users = new WeakMap();

const user1 = {
  name: 'John Doe',
};
const user2 = {
  name: 'Jane Doe',
};

users.set(user1, {
  email: 'johndoe@example.com',
});

users.set(user2, {
  email: 'janedoe@example.com',
});

Comme avec WeakSets, mettre la clé d’un objet WeakMap à null va implicitement mettre cet objet dans le ramasse-miettes :

user1 = null;

Ceci a les mêmes avantages qu’avec les WeakSets pour faciliter la gestion de la mémoire.

Conclusion

Dans cet article, nous avons examiné les Sets et les Maps et la façon dont ils traitent les éléments uniques et les paires clé-valeur respectivement. Ces structures de données sont très utiles et permettent de structurer et d’accéder plus facilement et plus efficacement aux données dans certains cas d’utilisation.

Des modifications spéciales telles que WeakSets et WeakMaps offrent plus d’options pour le développeur et sont pratiques pour la gestion de la mémoire.

Si vous avez aimé cet article (ou si vous y voyez quelques coquilles) n’hésitez pas à me mettre un petit commentaire 😉


siddhy

Développeur web full stack depuis une 15aine d'année dans une agence web du sud de la France et Geek depuis toujours, l'apprentissage et le partage font parti intégrante de ma philosophie au même titre que l'évolution personnelle et la sagesse bouddhiste.

2 commentaires

Loïc · 16 juillet 2019 à 14 h 43 min

Petite coquille dans l’exemple lié au paragraphe “Comment recupérer les éléments d’un ensemble (Set) javascript ? ” : il n’y a pas de donut dans l’initialisation du Set() 😉

const confectioneries = new Set([‘oreo’, ‘marshmallow’, ‘kitkat’, ‘oreo’,’gingerbread’]);

let iterator = confectioneries.values();

console.log( iterator.next()); // _{ value: ‘oreo’, done: false }
_
console.log( iterator.next()); // _{ value: ‘marshmallow’, done: false }
_
console.log( iterator.next()); //_ { value: ‘kitkat’, done: false }
_
console.log( iterator.next()); //_ { value: ‘gingerbread’, done: false }
_
console.log( iterator.next()); // _{ value: undefined, done: true }_

    siddhy · 16 juillet 2019 à 15 h 56 min

    Bien vu ! c’est la gourmandise qui a parlé :p
    Merci !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *