Patrząc na tę i tę stronę MDN, wydaje się, że jedyną różnicą między Mapami a WeakMaps jest brakująca właściwość „size” dla WeakMaps. Ale czy to prawda? Jaka jest między nimi różnica?
key
nie można zebrać, ponieważ odwołujesz się do niego.
key
nie można zebrać, ponieważ odwołujesz się do niego.
Odpowiedzi:
Na tej samej stronie w sekcji „ Dlaczego słaba mapa? ” :
Doświadczony programista JavaScript zauważy, że ten interfejs API można zaimplementować w JavaScript z dwiema tablicami (jedną dla kluczy, jedną dla wartości) współdzielonymi przez 4 metody API. Taka implementacja miałaby dwie główne niedogodności. Pierwszym jest wyszukiwanie O (n) (n to liczba kluczy na mapie). Drugi to problem z wyciekiem pamięci. W przypadku map napisanych ręcznie tablica kluczy zachowałaby odniesienia do kluczowych obiektów, zapobiegając ich usuwaniu jako śmieci. W natywnych WeakMaps odwołania do kluczowych obiektów są utrzymywane „słabo” , co oznacza, że nie zapobiegają one usuwaniu elementów bezużytecznych w przypadku, gdyby nie było innego odniesienia do obiektu.
Ponieważ odwołania są słabe, klucze WeakMap nie są wyliczalne (tj. Nie ma metody dającej listę kluczy). Gdyby tak było, lista zależałaby od stanu czyszczenia pamięci, wprowadzając niedeterminizm.
[I dlatego też nie mają size
własności]
Jeśli chcesz mieć listę kluczy, powinieneś ją utrzymywać samodzielnie. Istnieje również propozycja ECMAScript mająca na celu wprowadzenie prostych zestawów i map, które nie wykorzystywałyby słabych odniesień i byłyby wyliczalne.
- czyli „normalne” Map
s . Niewymienionych w MDN, ale na wniosek harmonii , ci mają również items
, keys
i values
metody generatora oraz wdrożenie Iterator
interfejsu .
new Map().get(x)
jest mniej więcej taki sam, jak odczyt właściwości ze zwykłego obiektu?
WeakMap
nadal ma tablicę (lub inną kolekcję) wpisów, po prostu informuje moduł odśmiecania pamięci, że są to słabe odwołania .
Oba zachowują się inaczej, gdy obiekt, do którego odwołują się ich klucze / wartości, zostanie usunięty. Weźmy poniższy przykładowy kod:
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);
})()
Powyższy IIFE jest wykonywany, nie ma możliwości odniesienia się do niego {x: 12}
i {y: 12}
już. Moduł wyrzucania elementów bezużytecznych działa dalej i usuwa wskaźnik klawisza b z „WeakMap”, a także usuwa {y: 12}
z pamięci. Ale w przypadku „Mapy”, garbage collector nie usuwa wskaźnika z „Map”, a także nie usuwa {x: 12}
z pamięci.
Podsumowanie: WeakMap pozwala garbage collectorowi wykonywać swoje zadanie, ale nie Map.
Źródła : http://qnimate.com/difference-between-map-and-weakmap-in-javascript/
map.entries().next().value // [{x:12}, 1]
WeakMap
może mieć tylko nieprymitywne klucze (bez łańcuchów, liczb lub Symbol
s jako kluczy, tylko tablice, obiekty, inne mapy itp.).
Map
ale nie wWeakMap
Może następne wyjaśnienie będzie dla kogoś bardziej jasne.
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
Jak widzisz, po wyjęciu k1
klucza z pamięci nadal mamy do niego dostęp wewnątrz mapy. W tym samym czasie usunięcie k2
klucza WeakMap usuwa go wm
również przez odniesienie.
Dlatego WeakMap nie ma wyliczalnych metod, takich jak forEach, ponieważ nie ma czegoś takiego jak lista kluczy WeakMap, są one po prostu odniesieniami do innych obiektów.
forEach
, (key, val)
należy być w rzeczywistości(val, key)
Kolejna różnica (źródło: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
Klucze WeakMaps są tylko typu Object. Prymitywne typy danych jako klucze są niedozwolone (np. Symbol nie może być kluczem WeakMap).
Jako WeakMap
klucza nie można też użyć ciągu, liczby ani wartości logicznej . A Map
może używać wartości pierwotnych dla kluczy.
w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key
m = new Map
m.set('a', 'b'); // Works
Z Javascript.info
Mapa - jeśli używamy obiektu jako klucza w zwykłej mapie, to gdy mapa istnieje, ten obiekt również istnieje. Zajmuje pamięć i nie może być usuwany jako śmieci.
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]
Podobnie, jeśli używamy obiektu jako klucza w zwykłej Mapie, to gdy Mapa istnieje, ten obiekt również istnieje. Zajmuje pamięć i nie może być usuwany jako śmieci
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 - Teraz, jeśli użyjemy w nim obiektu jako klucza i nie ma innych odniesień do tego obiektu - zostanie on automatycznie usunięty z pamięci (i mapy).
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference
// john is removed from memory!
WeapMap w javascript nie przechowuje żadnych kluczy ani wartości, po prostu manipuluje wartością klucza przy użyciu unikalnego identyfikatora i definiuje właściwość obiektu klucza.
ponieważ definiuje właściwość key object
według metody Object.definePropert()
, klucz nie może być typem pierwotnym .
a także ponieważ WeapMap nie zawiera w rzeczywistości par klucz-wartość, nie możemy uzyskać właściwości length ze słabe mapy.
a także manipulowana wartość jest przypisywana z powrotem do obiektu klucza, moduł odśmiecania pamięci może łatwo zebrać klucz, jeśli nie jest używany.
Przykładowy kod do implementacji.
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;
})();
odniesienie do realizacji
id
, ale powinno to być unikalne przez użycie czegoś Math.random i Date.now (), itp. I dodając ten dynamiczny identyfikator, można rozwiązać pierwszy punkt. Czy mógłbyś podać mi rozwiązanie dwóch ostatnich punktów.
WeakMap
klucze muszą być obiektami, a nie wartościami pierwotnymi.
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
Czemu????
Zobaczmy poniższy przykład.
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()
Jeśli użyjemy obiektu jako klucza w zwykłym
Map
, to dopókiMap
istnieje, ten obiekt również istnieje. Zajmuje pamięć i nie może być usuwany jako śmieci.
WeakMap
zasadniczo różni się pod tym względem. Nie zapobiega usuwaniu śmieci z kluczowych obiektów.
let user = { name: "User" };
let weakMap = new WeakMap();
weakMap.set(user, "...");
user = null; // overwrite the reference
// 'user' is removed from memory!
jeśli użyjemy w nim obiektu jako klucza i nie ma innych odniesień do tego obiektu - zostanie on automatycznie usunięty z pamięci (i mapy).
WeakMap
nie obsługuje iteracji i metod keys () , values () , entry () , więc nie ma możliwości uzyskania z nich wszystkich kluczy lub wartości.
WeakMap ma tylko następujące metody:
Jest to oczywiste, tak jakby obiekt stracił wszystkie inne odniesienia (jak „user” w powyższym kodzie), to ma zostać automatycznie zebrany jako śmieci. Ale technicznie nie jest dokładnie określone, kiedy nastąpi czyszczenie.
Decyduje o tym silnik JavaScript. Może zdecydować się na natychmiastowe wyczyszczenie pamięci lub zaczekać i wykonać czyszczenie później, gdy nastąpi więcej usunięć. Tak więc technicznie aktualna liczba elementów a WeakMap
nie jest znana. Silnik mógł go wyczyścić lub nie, lub zrobił to częściowo. Z tego powodu metody uzyskujące dostęp do wszystkich kluczy / wartości nie są obsługiwane.
Uwaga: - Głównym obszarem zastosowania WeakMap jest dodatkowe przechowywanie danych. Podobnie jak w przypadku buforowania obiektu, dopóki ten obiekt nie zostanie usunięty.