WeakMape WeakSet: Compreendendo referências fracas de JavaScript
Tags: javascript, tutorial
Published: 2022-12-28 17:39:41

Referências fracas não são usadas com frequência em JavaScript devido à forma como a linguagem é projetada. No entanto, em certas circunstâncias, eles podem ser vitais, como quando os desenvolvedores precisam armazenar dados adicionais e gerenciar automaticamente o uso da memória.

Neste post, aprenderemos sobre essas referências fracas em JavaScript e como podemos usá-las utilizando dois objetos dentro da linguagem: `WeakMape` `WeakSet`.

## Compreendendo referências fortes

Vamos começar dando uma olhada no que é uma referência normal ou forte em JavaScript. Em sua definição mais simples, uma referência forte é uma referência que mantém um objeto na memória. Vamos dar uma olhada na prática para entender do que estamos falando:

```jsx
let dog = { name: "badger" };

const pets = [dog];

dog = null;

console.log(pets); // [{ name: "badger" }]
```
Ao criar uma variável como um objeto, podemos colocar o objeto em uma array e remover a referência ao objeto original da variável que criamos, definindo seu valor como null.

Embora não possamos mais acessar o objeto através da variável `dog` porque há uma forte referência entre o array de pets e o objeto, o objeto é mantido na memória e pode ser acessado via `.pets[0]`

Em outras palavras, a referência forte impede a remoção do objeto da memória por meio da coleta de lixo.

## Entendendo referências fracas

É uma referência a um objeto que não impede a coleta de lixo se for a única referência ao objeto na memória.

Uma referência normal (considerada forte), impediria a coleta de lixo de um objeto mesmo que seja o único objeto que o referencia; este não é o caso de uma referência fraca.

Vamos pegar essa teoria e colocá-la em prática com o exemplo anterior de uma referência forte e colocá-la no contexto de uma referência fraca.

Ignore o uso do WeakMap agora; explicaremos isso com mais profundidade mais adiante neste artigo. Por enquanto, vamos ver o comportamento de referência fraca:

```jsx
let pets = new WeakMap();
let dog = { name: "badger" };

pets.set(dog, "okay");
console.log(pets); // WeakMap{ {...} -> "Okay" } <= cão definido para o WeakMap

dog = null; // Sobrescrever a referência ao objeto
console.log(pets); // WeakMap(0) <= cachorro foi coletado como lixo.
```
Ao utilizar o WeakMap e as referências fracas que o acompanham, podemos ver as diferenças entre os dois tipos de referências em ação.

Embora a referência forte (normal) ao objeto `dog` original ainda exista, o objeto `dog` persiste no WeakMap e podemos acessá-lo sem problemas.

Mas, quando sobrescrevemos a referência ao objeto `dog` original reatribuindo a variável como `null`, a única referência ao objeto original na memória é a referência fraca vinda do WeakMap que criamos.

Por ser uma referência fraca, não impedirá que a coleta de lixo ocorra. Isso significa que, quando o mecanismo JavaScript executar um processo de coleta de lixo novamente, o objeto `dog` será removido da memória e do local ao qual atribuímos o WeakMap.

A principal diferença a ser observada é que uma referência forte impede que um objeto seja coletado lixo, enquanto uma referência fraca não.

Por padrão, o JavaScript usa referências fortes para todas as suas referências e a única maneira de usar referências fracas é usar a **WeakMap** ou **WeakSet**.

## O que é coleta de lixo?

Embora a coleta de lixo seja um assunto detalhado e complicado, é importante entender ao discutir referências.

A coleta de garagem é um processo automatizado controlado pelo mecanismo JavaScript . Quando um valor é alcançável, é garantido que ele será armazenado na memória e não coletado no lixo, e há duas maneiras de um valor ser considerado alcançável.

A primeira é que eles fazem parte do conjunto básico de valores alcançáveis, como variáveis ​​globais, a função de execução atual e suas variáveis/parâmetros locais e mais valores internos.

A outra é alcançar qualquer valor da raiz por referência ou uma cadeia de referências. Por exemplo, imagine que criamos um objeto em uma variável global; este é alcançável pelo espaço global, portanto considerado alcançável.

Agora, se criarmos outro objeto e fizermos referência a ele a partir do objeto global que criamos, ele também poderá ser acessado porque é referenciado por meio do objeto global.

No entanto, se removermos o objeto global definindo-o como null, de repente aquele que poderíamos alcançar por referência não é alcançável, portanto, seria coletado como lixo.

Isso está especificamente referenciando referências fortes porque elas são o padrão em JavaScript. Mas, o mesmo se aplica a referências fracas, sendo a única exceção se a única referência a um objeto for fraca, não impedir a coleta de lixo e o objeto for removido.

Essa é uma visão geral de alto nível de como funciona a coleta de lixo; essencialmente, se algo não estiver acessível, ele será removido da memória para que a memória possa ser usada em outros locais.

## Sets vs. WeakSets

De acordo com o MDN, “Objetos Set são coleções de valores. Você pode iterar pelos elementos de um conjunto na ordem de inserção. Um valor no Conjunto pode ocorrer apenas uma vez; é único na coleção do Set."

Simplificando, um Set é como uma array que só pode conter valores únicos, mas ainda podemos iterá-la como uma array usando métodos como loops `for` e `.forEach`.

Semelhante a um Set, WeakSet é uma coleção de objetos que são únicos entre si, mas diferem porque WeakSet só pode armazenar objetos e não pode conter valores arbitrários de qualquer tipo, como strings ou números.

Em última análise, como o nome sugere, WeakSets são realmente fracos, o que significa que eles usam referências fracas.

Também vale a pena observar um efeito colateral interessante do uso de referências fracas é que WeakSet não é enumerável.

Isso significa que não há como percorrer os itens contidos nele porque não há uma lista de objetos atuais armazenados na coleção; eles são pouco referenciados e podem ser removidos a qualquer momento.

Aqui está um exemplo de WeakSet em uso e os métodos que podemos chamar nele:

```jsx
const pets = new WeakSet();
const cat = {name: "fluffy"};
const dog = {name: "badger"};

pets.add(cat);
pets.add(dog);

pets.has(cat);    // true
pets.has(dog);    // true

pets.delete(cat); // removes cat from the set
pets.has(cat);    // false, cat has been removed
pets.has(dog);    // true, dog is retained
```
## Maps vs. WeakMap

De acordo com o MDN , “O objeto Map contém pares chave-valor e lembra a ordem original de inserção das chaves. Qualquer valor (tanto objetos quanto valores primitivos) pode ser usado como uma chave ou um valor.”

Isso significa que a Map é como um objeto no qual podemos armazenar pares chave-valor e acessar os valores contidos em um Map por meio da chave. Ao contrário de um objeto padrão em JavaScript , no entanto, devemos usar o método para acessar os valores.`.get()`

Em comparação com a Map, a WeakMapé praticamente o mesmo, mas as referências que contém são referências fracas, o que significa que não impedirá a coleta de lixo de remover valores aos quais faz referência se não forem fortemente referenciados em outro lugar.

Além disso, WeakMaptem o mesmo efeito colateral de não ser enumerável devido às referências fracas.

Finalmente, devemos usar objetos como chaves, mas os valores podem ser qualquer valor arbitrário como uma string ou número. Aqui está um exemplo de uso de WeakMap e os métodos que podemos usar nele:

```jsx
const wm1 = new WeakMap();
const wm2 = new WeakMap();

const obj1 = {};
const obj2 = window;

wm1.set(obj1, 100);
wm1.set(obj2, 'Hello');
wm2.set(obj1, obj2); // You can set the value to be anything including an object or function
wm2.set(obj2, undefined); // Or, undefined
wm1.set(wm2, wm1); // Or, even a WeakMap itself

wm1.get(obj1); // 100

wm1.has(obj1); // true
wm1.delete(obj1);
wm1.has(obj1); // false
```
## Conclusão

Antes de encerrar, vamos considerar um possível caso de uso para referências fracas e os dois objetos que abordamos neste artigo.

Se você precisar armazenar dados adicionais temporariamente e não quiser se preocupar com a limpeza da memória ou como os objetos são removidos, usar referências fracas é um salva-vidas absoluto.

Mas, não é provável que você precise usar regularmente WeakMaps, WeakSetsou mesmo referências fracas regularmente em JavaScript.

Eles são úteis para situações ocasionais e ótimos para ter conhecimento básico, mas na maioria das situações, use referências normais (fortes).

Espero que você tenha achado útil este artigo sobre referências fracas em JavaScript.