Olhando esta e esta páginas MDN, parece que a única diferença entre Maps e WeakMaps é uma propriedade de "tamanho" ausente para WeakMaps. Mas isso é verdade? Qual é a diferença entre eles?
key
não pode ser coletado, porque é referenciado por você.
key
não pode ser coletado, porque é referenciado por você.
Respostas:
Na mesma página, seção " Por que o mapa fraco ? " :
O experiente programador de JavaScript notará que esta API pode ser implementada em JavaScript com dois arrays (um para chaves, um para valores) compartilhados pelos 4 métodos API. Tal implementação teria dois inconvenientes principais. O primeiro é uma pesquisa O (n) (sendo n o número de chaves no mapa). O segundo é um problema de vazamento de memória. Com mapas escritos manualmente, a matriz de chaves manteria as referências a objetos-chave, evitando que fossem coletados como lixo. Em WeakMaps nativos, as referências a objetos-chave são mantidas "fracamente" , o que significa que não evitam a coleta de lixo no caso de não haver outra referência ao objeto.
Como as referências são fracas, as chaves do WeakMap não são enumeráveis (ou seja, não há método que forneça uma lista das chaves). Se fossem, a lista dependeria do estado da coleta de lixo, introduzindo o não determinismo.
[E é por isso que eles também não têm size
propriedade]
Se você deseja ter uma lista de chaves, deve mantê-la você mesmo. Existe também uma proposta ECMAScript com o objetivo de introduzir conjuntos e mapas simples que não usariam referências fracas e seriam enumeráveis.
- quais seriam os "normais" Map
s . Não mencionados no MDN, mas na proposta harmonia , aqueles também têm items
, keys
e values
métodos de geradores e implementar a Iterator
interface de .
new Map().get(x)
tem aproximadamente o mesmo tempo look-up como a leitura de uma propriedade de um objeto simples?
WeakMap
ainda tem um array (ou outra coleção) de entradas, ele apenas informa ao coletor de lixo que essas são referências fracas .
Ambos se comportam de maneira diferente quando um objeto referenciado por suas chaves / valores é excluído. Vamos pegar o código de exemplo abaixo:
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);
})()
O IIFE acima é executado, não há como fazer referência {x: 12}
e {y: 12}
mais. O coletor de lixo vai em frente e exclui o ponteiro-chave b do “WeakMap” e também remove {y: 12}
da memória. Mas no caso do “Mapa”, o coletor de lixo não remove um ponteiro do “Mapa” e também não remove {x: 12}
da memória.
Resumo: WeakMap permite que o coletor de lixo faça sua tarefa, mas não Mapeie.
Referências: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/
map.entries().next().value // [{x:12}, 1]
WeakMap
só pode ter chaves não primitivas (sem strings ou números ou Symbol
s como chaves, apenas arrays, objetos, outros mapas, etc.).
Map
mas não noWeakMap
Talvez a próxima explicação seja mais clara para alguém.
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
Como você pode ver, após remover a k1
chave da memória, ainda podemos acessá-la dentro do mapa. Ao mesmo tempo, remover a k2
chave do WeakMap também a remove wm
por referência.
É por isso que o WeakMap não tem métodos enumeráveis como forEach, porque não existe uma lista de chaves do WeakMap, elas são apenas referências a outros objetos.
forEach
, (key, val)
deveria ser realmente(val, key)
Outra diferença (fonte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
Chaves de WeakMaps são apenas do tipo Object. Tipos de dados primitivos como chaves não são permitidos (por exemplo, um símbolo não pode ser uma chave WeakMap).
Nem uma string, número ou booleano podem ser usados como uma WeakMap
chave. A Map
pode usar valores primitivos para chaves.
w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key
m = new Map
m.set('a', 'b'); // Works
De Javascript.info
Mapa - se usarmos um objeto como a chave em um mapa normal, então, enquanto o mapa existir, esse objeto também existe. Ele ocupa memória e não pode ser coletado como lixo.
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]
Semelhante a isso, se usarmos um objeto como a chave em um Mapa normal, então, enquanto o Mapa existir, esse objeto também existe. Ele ocupa memória e não pode ser coletado
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 - Agora, se usarmos um objeto como a chave nele, e não houver outras referências a esse objeto - ele será removido da memória (e do mapa) automaticamente.
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference
// john is removed from memory!
WeapMap em javascript não contém nenhuma chave ou valor, ele apenas manipula o valor da chave usando um id único e define uma propriedade para o objeto chave.
porque define a propriedade key object
por método Object.definePropert()
, a chave não deve ser do tipo primitivo .
e também porque WeapMap não contém pares de valores-chave, não podemos obter a propriedade de comprimento de mapa fraco.
e também o valor manipulado é atribuído de volta ao objeto-chave, o coletor de lixo pode facilmente coletar a chave se não estiver em uso.
Código de amostra para implementação.
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;
})();
referência de implementação
id
, mas isso deve ser exclusivo usando algo Math.random e Date.now (), etc. E adicionando este id dinâmico, o primeiro ponto pode ser resolvido. Você poderia me fornecer uma solução para os dois últimos pontos.
WeakMap
as chaves devem ser objetos, não valores primitivos.
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
Por quê????
Vamos ver o exemplo abaixo.
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 usarmos um objeto como a chave em um regular
Map
, então, emboraMap
exista, esse objeto também existe. Ele ocupa memória e não pode ser coletado como lixo.
WeakMap
é fundamentalmente diferente neste aspecto. Não impede a coleta de lixo de objetos-chave.
let user = { name: "User" };
let weakMap = new WeakMap();
weakMap.set(user, "...");
user = null; // overwrite the reference
// 'user' is removed from memory!
se usarmos um objeto como a chave nele, e não houver outras referências a esse objeto - ele será removido da memória (e do mapa) automaticamente.
WeakMap
não suporta iteração e métodos keys () , values () , entradas () , portanto, não há como obter todas as chaves ou valores dele.
O WeakMap possui apenas os seguintes métodos:
Isso é óbvio, como se um objeto tivesse perdido todas as outras referências (como 'usuário' no código acima), então ele deve ser coletado como lixo automaticamente. Mas tecnicamente não é exatamente especificado quando a limpeza acontece.
O mecanismo JavaScript decide isso. Ele pode optar por realizar a limpeza da memória imediatamente ou aguardar e fazer a limpeza mais tarde, quando ocorrerem mais exclusões. Portanto, tecnicamente, a contagem atual de elementos de a WeakMap
não é conhecida. O motor pode ter limpado ou não ou feito parcialmente. Por esse motivo, os métodos que acessam todas as chaves / valores não são suportados.
Nota: - A principal área de aplicação do WeakMap é um armazenamento de dados adicional. Como armazenar um objeto em cache até que o lixo seja coletado.