ECMAScript 6: à quoi sert WeakSet?

Le WeakSet est censé stocker des éléments par référence faible. Autrement dit, si un objet n'est référencé par aucune autre chose, il doit être nettoyé à partir du WeakSet.

J'ai écrit le test suivant:

var weakset = new WeakSet(), numbers = [1, 2, 3]; weakset.add(numbers); weakset.add({name: "Charlie"}); console.log(weakset); numbers = undefined; console.log(weakset); 

Bien que mon tableau [1, 2, 3] ne soit pas référencé par quelque chose, il n'est pas supprimé du WeakSet. La console imprime:

 WeakSet {[1, 2, 3], Object {name: "Charlie"}} WeakSet {[1, 2, 3], Object {name: "Charlie"}} 

Pourquoi donc?

De plus, j'ai une autre question. Quel est l'intérêt d'ajouter des objets à WeakSets directement, comme ceci:

 weakset.add({name: "Charlie"}); 

Les traces de Traceur sont-elles ou est-ce que je manque quelque chose?

Et enfin, quelle est l'utilisation pratique de WeakSet si nous ne pouvons même pas itérer à travers elle ni obtenir la taille actuelle?

Il ne se retire pas du WeakSet. Pourquoi donc?

Très probablement parce que le collecteur d'ordures n'a pas encore fonctionné. Cependant, vous dites que vous utilisez Traceur, alors il se pourrait simplement qu'ils ne soient pas correctement pris en charge. Je me demande comment la console peut afficher le contenu d'un WeakSet toute façon.

Quel est l'intérêt d'ajouter des objets à WeakSets directement?

Il est absolument impossible d'ajouter des littéraux d'objet à WeakSet s.

Quelle est l'utilisation pratique de WeakSet si nous ne pouvons même pas l'itérer à travers elle ni obtenir la taille actuelle?

Tout ce que vous pouvez obtenir est un bit d'information: l'objet (ou génériquement, la valeur) est-il contenu dans l'ensemble?

Cela peut être utile dans les situations où vous souhaitez "marquer" des objets sans les modifier en même temps (en définissant une propriété). Beaucoup d'algorithmes contiennent une sorte de condition "si x était déjà vue" (une détection de cycle JSON.stringify pourrait être un bon exemple), et lorsque vous travaillez avec des valeurs fournies par l'utilisateur, l'utilisation d'un Set / WeakSet serait souhaitable. L'avantage d'un WeakSet ici est que son contenu peut être récupéré lorsque votre algorithme est toujours en cours d'exécution, ce qui permet de réduire la consommation de mémoire (ou même d'éviter les fuites) lorsque vous rencontrez beaucoup de données qui sont paresseuses (peut-être même de manière asynchrone ) Produit.

C'est une question très difficile. Pour être complètement honnête, je n'avais aucune idée dans le contexte de JavaScript, alors j'ai demandé dans esdiscuss et obtenu une réponse convaincante de Domenic .

WeakSets est utile pour des raisons de sécurité et de validation . Si vous voulez pouvoir isoler un morceau de JavaScript. Ils vous permettent de marquer un objet pour indiquer qu'il appartient à un ensemble spécial d'objets.

Disons que j'ai une classe ApiRequest :

 class ApiRequest { constructor() { // bring object to a consistent state, use platform code you have no cirect access to } makeRequest() { // do work } } 

Maintenant, j'écris une plate-forme JavaScript – ma plate-forme vous permet d'exécuter JavaScript pour faire des appels – pour faire ces appels, vous avez besoin d'un ApiRequest – Je ne veux que faire ApiRequest avec les objets que je vous donne afin que vous ne puissiez pas contourner Toutes les contraintes que j'ai mises en place.

Cependant, au moment où rien ne vous empêche de faire:

 ApiRequest.prototype.makeRequest.call(null, args); // make request as function Object.create(ApiRequest.prototype).makeRequest(); // no initialization function Foo(){}; Foo.prototype = ApiRequest.prototype; new Foo().makeRequest(); // no super 

Et ainsi de suite, notez que vous ne pouvez pas conserver une liste normale ou un ensemble d'objets ApiRequest , car cela empêcherait qu'ils ne soient collectés. À part une fermeture, tout peut être réalisé avec des méthodes publiques comme Object.getOwnPropertyNames ou Object.getOwnSymbols . Donc, vous êtes en train de me faire et de faire:

 const requests = new WeakSet(); class ApiRequest { constructor() { requests.add(this); } makeRequest() { if(!request.has(this)) throw new Error("Invalid access"); // do work } } 

Maintenant, peu importe ce que je fais – je dois détenir un objet ApiRequest valide pour appeler la méthode makeRequest . Ceci est impossible sans WeakMap / WeakSet.

Donc, en bref – WeakMaps sont utiles pour écrire des plates-formes dans JavaScirpt . Normalement, ce type de validation se fait sur le côté C ++, mais l'ajout de ces fonctions permettra de déplacer et de créer des éléments en JavaScript.

(Bien sûr, tout un WeakSet fait un WeakMap qui mappe les valeurs à true peut également le faire, mais c'est vrai pour toute construction map / set)

(Comme le suggère la réponse de Bergi, il n'y a jamais de raison d'ajouter un littéral d'objet directement à un WeakMap ou à un WeakSet )

Par définition, WeakSet n'a que trois fonctionnalités clés

  • Reliez faiblement un objet à l'ensemble
  • Supprimez un lien vers un objet de l'ensemble
  • Vérifiez si un objet a déjà été lié à l'ensemble

Cela semble plus familier?

Dans certaines applications, les développeurs devront peut-être mettre en place un moyen rapide d'itérer à travers une série de données qui sont polluées par beaucoup et beaucoup de redondance mais que vous souhaitez choisir uniquement celles qui n'ont pas été traitées avant (unique) . WeakSet pourrait vous aider. Voir un exemple ci-dessous:

 var processedBag = new WeakSet(); var nextObject = getNext(); while (nextObject !== null){ // Check if already processed this similar object? if (!processedBag.has(nextObject)){ // If not, process it and memorize process(nextObject); processedBag.add(nextObject); } nextObject = getNext(); } 

L'une des meilleures structures de données pour l'application ci-dessus est le filtre Bloom qui est très bon pour une grande taille de données. Cependant, vous pouvez également appliquer l'utilisation de WeakSet à cette fin.

WeakSet est une simplification de WeakMap pour laquelle votre valeur va toujours être booléenne. Il vous permet de marquer des objets JavaScript afin de ne plus faire quelque chose avec eux qu'une seule fois ou de maintenir leur état à l'égard d'un certain processus. En théorie car il n'a pas besoin de tenir une valeur, il devrait utiliser un peu moins de mémoire et effectuer un peu plus vite que WeakMap.

 var touch = (function() { var seen = new WeakSet(); return function(value) { if(seen.has(value)) return true; seen.add(value); }; })(); function convert(object) { if(touch(object)) return; extend(object, yunoprototype); // Made up. }; function unconvert(object) { if(untouch(object)) return; // Imagine it exists. del_props(object, Object.keys(yunoprototype)); // Never do this IRL. };