Guardando questa e questa pagina MDN sembra che l'unica differenza tra Maps e WeakMaps sia una proprietà "size" mancante per WeakMaps. Ma è vero? Qual è la differenza tra loro?
key
non può essere raccolto, perché è referenziato da te.
key
non può essere raccolto, perché è referenziato da te.
Risposte:
Dalla stessa pagina, sezione " Why Weak Map? " :
Il programmatore JavaScript esperto noterà che questa API potrebbe essere implementata in JavaScript con due array (uno per le chiavi, uno per i valori) condivisi dai 4 metodi API. Una simile implementazione avrebbe due principali inconvenienti. Il primo è una ricerca O (n) (n è il numero di chiavi nella mappa). Il secondo è un problema di perdita di memoria. Con le mappe scritte manualmente, l'array di chiavi manterrebbe i riferimenti agli oggetti chiave, impedendo che vengano raccolti in modo indesiderato. Nelle WeakMap native, i riferimenti agli oggetti chiave vengono mantenuti "debolmente" , il che significa che non impediscono la raccolta dei rifiuti nel caso in cui non ci siano altri riferimenti all'oggetto.
Poiché i riferimenti sono deboli, le chiavi WeakMap non sono enumerabili (cioè non esiste un metodo che ti dia un elenco delle chiavi). Se lo fossero, l'elenco dipenderebbe dallo stato della garbage collection, introducendo il non determinismo.
[Ed è per questo che anche loro non hanno size
proprietà]
Se vuoi avere un elenco di chiavi, dovresti mantenerlo da solo. C'è anche una proposta ECMAScript che mira a introdurre semplici insiemi e mappe che non utilizzerebbero riferimenti deboli e sarebbero enumerabili.
- che sarebbero i "normali" Map
s . Non menzionato in MDN, ma nella proposta di armonia , quelli hanno anche items
, keys
e values
metodi di generatore e implementare l' Iterator
interfaccia .
new Map().get(x)
ha circa lo stesso tempo di ricerca della lettura di una proprietà da un oggetto semplice?
WeakMap
ha ancora un array (o un'altra raccolta) di voci, dice semplicemente al garbage collector che si tratta di riferimenti deboli .
Entrambi si comportano in modo diverso quando un oggetto a cui fanno riferimento le loro chiavi / valori viene eliminato. Prendiamo il seguente codice di esempio:
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 di cui sopra viene eseguito, non è possibile fare riferimento {x: 12}
e non è {y: 12}
più. Garbage Collector va avanti e cancella il puntatore chiave b da "WeakMap" e rimuove anche {y: 12}
dalla memoria. Ma in caso di "Map", il garbage collector non rimuove un puntatore da "Map" e inoltre non rimuove {x: 12}
dalla memoria.
Riepilogo: WeakMap consente a Garbage Collector di svolgere il proprio compito ma non Map.
Riferimenti: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/
map.entries().next().value // [{x:12}, 1]
WeakMap
può avere solo chiavi non primitive (nessuna stringa o numero o Symbol
s come chiavi, solo array, oggetti, altre mappe, ecc.).
Map
ma non inWeakMap
Forse la prossima spiegazione sarà più chiara per qualcuno.
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
Come vedi, dopo aver rimosso la k1
chiave dalla memoria possiamo ancora accedervi all'interno della mappa. Allo stesso tempo, la rimozione della k2
chiave di WeakMap la rimuove wm
anche per riferimento.
Ecco perché WeakMap non ha metodi enumerabili come forEach, perché non esiste un elenco di chiavi WeakMap, sono solo riferimenti ad altri oggetti.
forEach
, (key, val)
dovrebbe essere effettivamente(val, key)
Un'altra differenza (fonte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
Le chiavi di WeakMaps sono solo del tipo Object. I tipi di dati primitivi come chiavi non sono consentiti (ad esempio, un simbolo non può essere una chiave WeakMap).
Né è possibile utilizzare una stringa, un numero o un valore booleano come WeakMap
chiave. A Map
può usare valori primitivi per le chiavi.
w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key
m = new Map
m.set('a', 'b'); // Works
A partire dal Javascript.info
Mappa : se usiamo un oggetto come chiave in una mappa normale, finché esiste la mappa, esiste anche quell'oggetto. Occupa memoria e potrebbe non essere sottoposto a Garbage Collection.
let john = { name: "John" };
let array = [ john ];
john = null; // overwrite the reference
// john is stored inside the array, so it won't be garbage-collected
// we can get it as array[0]
In modo simile, se usiamo un oggetto come chiave in una mappa normale, finché esiste la mappa, esiste anche quell'oggetto. Occupa memoria e potrebbe non essere sottoposto a Garbage Collection
let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // overwrite the reference
// john is stored inside the map,
// we can get it by using map.keys()
WeakMap - Ora, se usiamo un oggetto come chiave in esso e non ci sono altri riferimenti a quell'oggetto, verrà rimosso automaticamente dalla memoria (e dalla mappa).
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference
// john is removed from memory!
WeapMap in javascript non contiene alcuna chiave o valore, manipola semplicemente il valore della chiave utilizzando un ID univoco e definisce una proprietà per l'oggetto chiave.
poiché definisce la proprietà in key object
base al metodo Object.definePropert()
, la chiave non deve essere di tipo primitivo .
e anche poiché WeapMap non contiene effettivamente coppie di valori chiave, non possiamo ottenere la proprietà length di weakmap.
e anche il valore manipolato viene assegnato all'oggetto chiave, il garbage collector può facilmente raccogliere la chiave se non viene utilizzata.
Codice di esempio per l'implementazione.
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;
})();
riferimento di attuazione
id
, ma questo dovrebbe essere unico usando qualcosa di Math.random e Date.now (), ecc. E aggiungendo questo id dinamico, il primo punto può essere risolto. Potrebbe fornirmi una soluzione per gli ultimi due punti.
WeakMap
le chiavi devono essere oggetti, non valori primitivi.
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
Perché????
Vediamo sotto l'esempio.
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()
Se usiamo un oggetto come chiave in un normale
Map
, allora mentre ilMap
esiste, esiste anche quell'oggetto. Occupa memoria e potrebbe non essere sottoposto a Garbage Collection.
WeakMap
è fondamentalmente diverso in questo aspetto. Non impedisce la garbage collection di oggetti chiave.
let user = { name: "User" };
let weakMap = new WeakMap();
weakMap.set(user, "...");
user = null; // overwrite the reference
// 'user' is removed from memory!
se usiamo un oggetto come chiave al suo interno e non ci sono altri riferimenti a quell'oggetto, verrà rimosso automaticamente dalla memoria (e dalla mappa).
WeakMap
non supporta iterazioni e metodi keys () , values () , entry () , quindi non c'è modo di ottenere tutte le chiavi oi valori da esso.
WeakMap ha solo i seguenti metodi:
È ovvio come se un oggetto avesse perso tutti gli altri riferimenti (come "utente" nel codice sopra), quindi deve essere raccolto automaticamente. Ma tecnicamente non è esattamente specificato quando avviene la pulizia.
Il motore JavaScript lo decide. Può scegliere di eseguire immediatamente la pulizia della memoria o di attendere ed eseguire la pulizia in un secondo momento quando si verificano più eliminazioni. Quindi, tecnicamente il conteggio degli elementi correnti di a WeakMap
non è noto. Il motore potrebbe averlo ripulito o meno o lo ha fatto parzialmente. Per questo motivo, i metodi che accedono a tutte le chiavi / valori non sono supportati.
Nota: - L'area principale di applicazione di WeakMap è una memoria dati aggiuntiva. Come la memorizzazione nella cache di un oggetto fino a quando tale oggetto non viene raccolto dalla spazzatura.