JavaScript WeakMap et WeakSet

Dans le chapitre Collection d'ordures, il a été déclaré que le moteur JavaScript peut stocker une valeur en mémoire une fois qu'elle est atteignable.

Voici un exemple:

Javascript remove object from memory
let js = { name: "Javascript" }; // object can be accessed, js is the reference to it // rewrite the reference js = null; // the object will be deleted from memory console.log(js);

En règle générale, les propriétés ou éléments de structures de données telles qu'un objet ou un tableau sont atteignables et conservés en mémoire une fois que cette structure de données est en mémoire. Par exemple, après avoir mis un objet dans un tableau, il existera aussi longtemps que le tableau existera.

Voici un exemple:

Javascript cache a function result
let js = { name: "Javascript" }; let array = [js]; js = null; // rewrite the reference // js is stored in an array, so it will not garbage-collected // it can be received as an array[0] console.log(js);

De manière correspondante, l'application d'un objet comme la clé dans un Map régulière, il existera aussi longtemps que le plan existe.

Un exemple ressemblera à ce qui suit:

Javascript cache a function result
let js = { name: "Javascript" }; let map = new Map(); map.set(js, "..."); js = null; // rewriting the reference // js is on the map, // it can be received by using map.keys() console.log(js);

De plus, nous allons couvrir WeakMap, qui est complètement différent et ne s'abstient pas de la collecte d'ordures des objets clés.

WeakMap

La principale différence entre Map et WeakMap est que la clé du WeakMap ne peut pas être des valeurs primitives. Ils doivent être des objets, comme dans l'exemple ci-dessous:

Javascript WeakMap
let weakMap = new WeakMap(); let obj = {}; key1 = weakMap.set(obj, "ok"); // works fine, object key console.log(key1); // can't use string as key key2 = weakMap.set("test", "Oops"); // Error because the “test” is not an object console.log(key2);

Les itérations et les méthodes keys(), values(), entries() ne sont pas supportées par WeakMap.

Les méthodes, supportées par WeakMap sont les suivantes: weakMap.get(key), weakMap.set(key, value), weakMap.has(key), et weakMap.delete(key).

weakMap.delete(key)

Le stockage supplémentaire de données est le principal domaine d'application pour WeakMap. WeakMap est particulièrement utile pour stocker des données associées à une bibliothèque tierce. Par exemple, envisagez de mettre les données dans un WeakMap, avec un objet comme clé. Une fois l'objet collecté comme ordure, les données disparaîtront également automatiquement comme le montre ci-dessous:

let weakMap = new WeakMap();
let obj = {
  name: "test"
};
key = weakMap.set(obj, "test docs");
// if obj disappears, test docs will be automatically destroyed

Maintenant, imaginez avoir un code qui maintient un compteur de visites pour les utilisateurs. L'information est conservée dans une carte, avec un objet utilisateur comme clé et le nombre de visites comme valeur.

Après le départ d'un utilisateur, vous avez l'intention d'arrêter de stocker leur nombre de visites.

Tout d'abord, voyons un exemple de fonction de comptage avec Map. Cela ressemblera à ce qui suit:

Javascript WeakMap additional data
// visitsCount.js let visitsCountMap = new Map(); // map: book => visits count // increase the visits count function countBook(book) { let count = visitsCountMap.get(book) || 0; visitsCountMap.set(book, count + 1); console.log(count); } // main.js let js = { name: "Javascript" }; countBook(js); // count his visits countBook(js); // count his visits // later js leaves us js = null; console.log(js);

Ainsi, lors de la suppression des utilisateurs, il est nécessaire de nettoyer visitsCountMap. D'une autre manière, il sera stocké en mémoire indéfiniment.

Cependant, le nettoyage de cette façon peut parfois devenir une tâche ennuyeuse. Si vous voulez l'éviter, vous pouvez vous référer à WeakMap. Voici un exemple d'utilisation de WeakMap à la place de ce genre de nettoyage:

Javascript WeakMap additional data
// visitsCount.js let visitsCountMap = new WeakMap(); // weakmap: book => visits count // increase the visits count function countBook(book) { let count = visitsCountMap.get(book) || 0; visitsCountMap.set(book, count + 1); console.log(count); } // main.js let js = { name: "Javascript" }; countBook(js); // count his visits countBook(js); // count his visits // later js leaves us js = null; console.log(js);

Maintenant, il n'est plus nécessaire de nettoyer visitsCountMap.

A propos du Caching

Le caching se produit lorsqu'un résultat de fonction doit être mémorisé (mis en cache) pour être réutilisé plus tard lors de l'appel sur le même objet.

Map peut être utilisé pour stocker les résultats comme suit:

Javascript cache a function result
// cache.js let cache = new Map(); // calculate and remember the result function process(myObj) { if (!cache.has(myObj)) { let res = /* result calculations for */ myObj; cache.set(myObj, res); } return cache.get(myObj); } // Now we use process() in another file: // main.js let myObj = { /* let's say we have an object */ }; let res1 = process(myObj); // calculated // later from another place in the code let res2 = process(myObj); // the result taken from the cache is remembered // later when an object is no longer needed: myObj = null; console.log(cache.size); // 1

Dans le cas de l'appel à process(obj) avec le même objet plusieurs fois, il calculera le résultat seulement la première fois. Ensuite, il prendra l'information du cache.

Le seul inconvénient du caching est que vous devez nettoyer le cache une fois que vous n'avez plus besoin de l'objet.

Remplacer Map par WeakMap résoudra le problème. L'information mise en cache sera supprimée de la mémoire automatiquement une fois que l'objet aura été collecté comme ordure.

Pour être plus précis, considérons l'exemple ci-dessous:

// cache.js
let cache = new WeakMap();
// calculate and remember the result
function process(obj) {
  if (!cache.has(obj)) {
    let res = /* calculate the result for */ obj;
    cache.set(obj, res);
  }
  return cache.get(obj);
}
 
// main.js
let obj = { /* some object */ };
let res1 = process(obj);
let res2 = process(obj);
// later, when object is no longer needed:
obj = null;
// Can not get cache.size because it is  WeakMap,
// but it is 0 or soon will be 0
//Once object gets garbage collected, the cached data will also be cleaned

WeakSet

WeakSet est considéré comme équivalent à Set. Cependant, seuls les objets et non les primitives peuvent être ajoutés à WeakSet.

Un objet est situé dans l'ensemble tant qu'il est atteignable ailleurs.

WeakSet prend également en charge has, add et delete. Mais il n'y a pas d'itérations ou de size et de keys() qui sont supportées.

De plus, il peut servir de stockage supplémentaire pour les données, mais pas pour des données arbitraires. Voici un exemple d'ajout de langues à WeakSet pour garder une trace de celles qui ont créé le site:

Javascript WeakSet
let createdSet = new WeakSet(); let html = { name: "Html" }; let php = { name: "php" }; let js = { name: "Javascript" }; createdSet.add(html); // Html created us createdSet.add(js); // Then Javascript createdSet.add(html); // Html again // createdSet has 2 languages now // check if html created? console.log(createdSet.has(html)); // true // check if php created? console.log(createdSet.has(php)); // false html = null; // createdSet will be cleaned automatically

Il y a une limitation significative dans WeakMap et WeakSet: il n'y a pas d'itérations. Il n'y a pas non plus de possibilité de recevoir tout le contenu actuel.

Résumé

Dans ce chapitre, nous avons couvert WeakMap et WeakSet.

En résumé, nous pouvons dire que WeakMap est considéré comme une collection de type Map, permettant uniquement aux objets d'être des clés. Il les supprime ainsi que la valeur associée lorsqu'ils deviennent inaccessibles.

WeakSet est considéré comme une collection de type Set, ne stockant que des objets et les supprimant lorsqu'ils deviennent inaccessibles.

Les deux collections ne supportent pas les propriétés et méthodes ne se référant pas à toutes les clés ou au comptage de celles-ci. Ils ne permettent que des opérations individuelles.

Heure du Quiz : Testez Vos Compétences!

Prêt à relever le défi de ce que vous avez appris ? Plongez dans nos quiz interactifs pour approfondir votre compréhension et renforcer vos connaissances de manière ludique.

Trouvez-vous cela utile?