web-dev-qa-db-fra.com

Quelle est la différence entre ES6 Map et WeakMap?

En regardant ceci et ceci les pages MDN, il semble que la seule différence entre Maps et WeakMaps est une propriété de "taille" manquante pour WeakMaps. Mais est-ce vrai? Quelle est la différence entre eux?

83
Dmitrii Sorin

De la même page, section " Pourquoi Carte faible ?" :

Le programmeur JavaScript expérimenté remarquera que cette API pourrait être implémentée en JavaScript avec deux tableaux (un pour les clés, un pour les valeurs) partagés par les 4 méthodes de l'API. Une telle mise en œuvre aurait deux inconvénients principaux. Le premier est une recherche O(n) (n étant le nombre de clés dans la carte). Le second est un problème de fuite de mémoire. Avec des cartes écrites manuellement, le tableau de clés conserverait les références aux objets clés, les empêchant d'être récupérés. Dans les WeakMaps natifs, les références aux objets clés sont conservées "faiblement" , ce qui signifie qu'ils n'empêchent pas la récupération de place au cas où il n'y aurait pas d'autre référence à l'objet.

En raison de la faiblesse des références, les clés WeakMap ne sont pas énumérables (c'est-à-dire qu'aucune méthode ne vous donne une liste des clés). S'ils l'étaient, la liste dépendrait de l'état de la collecte des ordures, introduisant le non-déterminisme.

[Et c'est pourquoi ils n'ont pas de propriété size aussi]

Si vous souhaitez avoir une liste de clés, vous devez la maintenir vous-même. Il existe également une proposition ECMAScript visant à introduire des ensembles et des cartes simples qui n'utiliseraient pas de références faibles et seraient énumérables.

- qui serait le "normal" Maps . Non mentionné au MDN, mais dans la proposition d'harmonie , ceux-ci ont également les méthodes de générateur items, keys et values et implémentent Iterator interface .

46
Bergi

Ils se comportent tous deux différemment lorsqu'un objet référencé par leurs clés/valeurs est supprimé. Prenons l'exemple de code ci-dessous:

var map = new Map();
var weakmap = new WeakMap();

(function(){
    var a = {x: 12};
    var b = {y: 12};

    map.set(a, 1);
    weakmap.set(b, 2);
})()

L'IIFE ci-dessus est exécuté, il n'y a aucun moyen de référencer {x: 12} et {y: 12} plus. Le ramasse-miettes va de l'avant et supprime le pointeur clé b de "WeakMap" et supprime également {y: 12} de mémoire. Mais dans le cas de "Map", le garbage collector ne supprime pas un pointeur de "Map" et ne supprime pas non plus {x: 12} de mémoire.

Résumé: WeakMap permet au ramasse-miettes de faire sa tâche mais pas de mapper.

Références: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/

83
kshirish

Peut-être que la prochaine explication sera plus claire pour quelqu'un.

var k1 = {a: 1};
var k2 = {b: 2};

var map = new Map();
var wm = new WeakMap();

map.set(k1, 'k1');
wm.set(k2, 'k2');

k1 = null;
map.forEach(function (val, key) {
    console.log(key, val); // k1 {a: 1}
});

k2 = null;
wm.get(k2); // undefined

Comme vous le voyez, après avoir supprimé k1 clé de la mémoire, nous pouvons toujours y accéder à l'intérieur de la carte. En même temps, supprimer k2 la clé de WeakMap la supprime également de wm par référence.

C'est pourquoi WeakMap n'a pas de méthodes énumérables comme forEach, car il n'existe pas de liste de clés WeakMap, ce ne sont que des références à d'autres objets.

64
Rax Wunter

Une autre différence (source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):

Les clés de WeakMaps sont du type Object uniquement. Les types de données primitifs comme clés ne sont pas autorisés (par exemple, un symbole ne peut pas être une clé WeakMap).

Une chaîne, un nombre ou un booléen ne peut pas non plus être utilisé comme clé WeakMap. Un Map peut utiliser des valeurs primitives pour les clés.

w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key

m = new Map
m.set('a', 'b'); // Works
32
Trevor Dixon

WeapMap en javascript ne contient aucune clé ou valeur, il manipule simplement la valeur de clé en utilisant un id unique et définit la propriété de l'objet clé.

car elle définit la propriété à key par la méthode Object.definePropert(), la clé ne doit pas être de type primitif.

et aussi parce que WeapMap ne contient pas réellement de paires clé-valeur, nous ne pouvons pas obtenir la propriété length de faiblesse.

et la valeur manipulée est également affectée à la clé, le garbage collector peut facilement collecter la clé si elle ne sert à rien.

Exemple de code pour l'implémentation.

if(typeof WeapMap != undefined){
return;
} 
(function(){
   var WeapMap = function(){
      this.__id = '__weakmap__';
   }

   weakmap.set = function(key,value){
       var pVal = key[this.__id];
        if(pVal && pVal[0] == key){
           pVal[1]=value;
       }else{
          Object.defineProperty(key, this.__id, {value:[key,value]});
          return this;
        }
   }

window.WeakMap = WeakMap;
})();

référence de implémentation

2
Ravi Sevta

Les clés WeakMap doivent être des objets et non des valeurs primitives.

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok"); // works fine (object key)

// can't use a string as the key
weakMap.set("test", "Not ok"); // Error, because "test" is not an object

Pourquoi ????

Voyons l'exemple ci-dessous.

let user = { name: "User" };

let map = new Map();
map.set(user, "...");

user = null; // overwrite the reference

// 'user' is stored inside the map,
// We can get it by using map.keys()

Si nous utilisons un objet comme clé dans un Map normal, alors que le Map existe, cet objet existe également. Il occupe de la mémoire et ne peut pas être récupéré.

WeakMap est fondamentalement différent à cet égard. Cela n'empêche pas le ramasse-miettes des objets clés.

let user = { name: "User" };

let weakMap = new WeakMap();
weakMap.set(user, "...");

user = null; // overwrite the reference

// 'user' is removed from memory!

si nous utilisons un objet comme clé, et qu'il n'y a pas d'autres références à cet objet - il sera automatiquement supprimé de la mémoire (et de la carte).

WeakMapne fonctionne pas supporte l'itération et les méthodes touches () , valeurs () , entrées () , il n'y a donc aucun moyen d'en obtenir toutes les clés ou valeurs.

WeakMap n'a que les méthodes suivantes:

  • faiblesseMap.get (clé)
  • faiblesseMap.set (clé, valeur)
  • faiblesseMap.delete (clé)
  • faiblesseMap.has (clé)

C'est évident comme si un objet avait perdu toutes les autres références (comme 'user' dans le code ci-dessus), alors il doit être récupéré automatiquement. Mais techniquement, ce n'est pas exactement spécifié quand le nettoyage a lieu.

Le moteur JavaScript décide cela. Il peut choisir d'effectuer le nettoyage de la mémoire immédiatement ou d'attendre et de faire le nettoyage plus tard lorsque d'autres suppressions se produisent. Donc, techniquement, le nombre actuel d'éléments d'un WeakMap n'est pas connu. Le moteur peut l'avoir nettoyé ou non ou l'a fait partiellement. Pour cette raison, les méthodes qui accèdent à toutes les clés/valeurs ne sont pas prises en charge.

Remarque: - Le principal domaine d'application de WeakMap est un stockage de données supplémentaire. Comme la mise en cache d'un objet jusqu'à ce que cet objet soit récupéré.

0
Pravin Divraniya