<h2>Symbols: Criando Identificadores Únicos</h2>
<p>Symbols são primitivos únicos em JavaScript que servem como identificadores imutáveis. Diferentemente de strings, dois symbols nunca serão iguais, mesmo que criados com a mesma descrição. Isso os torna ideais para criar chaves privadas em objetos, evitando colisões de nomes e protegendo dados sensíveis de acesso acidental.</p>
<pre><code class="language-javascript">// Criando symbols
const idPrivado = Symbol('id');
const permissao = Symbol('admin');
const usuario = {
nome: 'João',
[idPrivado]: 12345,
[permissao]: false
};
console.log(usuario.nome); // 'João'
console.log(usuario[idPrivado]); // 12345
console.log(Object.keys(usuario)); // ['nome'] - symbols não aparecem!</code></pre>
<p>Um caso de uso real é criar propriedades privadas em classes sem expor internals. Symbols não aparecem em iterações com <code>for...in</code>, <code>Object.keys()</code> ou <code>JSON.stringify()</code>, tornando-os perfeitos para dados que devem existir mas não serem enumeráveis. Use <code>Symbol.for()</code> quando precisar de symbols compartilhadas entre contextos (como iframes ou workers).</p>
<pre><code class="language-javascript">// Exemplo em produção: classe com dados privados
class ContaBancaria {
#saldo = 0; // Alternativa moderna (private fields)
constructor(titular, saldoInicial) {
this.titular = titular;
this.#saldo = saldoInicial;
}
depositar(valor) {
this.#saldo += valor;
}
obterSaldo() {
return this.#saldo;
}
}
const conta = new ContaBancaria('Maria', 1000);
conta.depositar(500);
console.log(conta.obterSaldo()); // 1500
console.log(conta.saldo); // undefined - protegido!</code></pre>
<h2>WeakMap: Mapeamentos com Referências Fracas</h2>
<p>WeakMap é um tipo de mapa que mantém referências fracas às suas chaves. Isso significa que se a chave for deletada da memória, a entrada correspondente será automaticamente removida do WeakMap. Diferentemente de Map comum, WeakMap só aceita objetos como chaves e não é iterável.</p>
<pre><code class="language-javascript">// WeakMap na prática
const cachePrivado = new WeakMap();
class Usuario {
constructor(nome) {
this.nome = nome;
}
obterMetadados() {
if (!cachePrivado.has(this)) {
cachePrivado.set(this, {
criadoEm: new Date(),
acessoTotal: 0
});
}
const meta = cachePrivado.get(this);
meta.acessoTotal++;
return meta;
}
}
let usuario1 = new Usuario('Pedro');
console.log(usuario1.obterMetadados()); // { criadoEm: ..., acessoTotal: 1 }
console.log(usuario1.obterMetadados()); // { criadoEm: ..., acessoTotal: 2 }
usuario1 = null; // Quando deletado, WeakMap libera automaticamente</code></pre>
<p>Na produção, WeakMap é excelente para associar dados privados a DOM nodes ou instâncias de classe. Evita memory leaks porque os dados são automaticamente coletados quando o objeto é deletado. Use-a para caching de metadados, eventos privados ou informações vinculadas a objetos específicos que podem ser destruídos.</p>
<pre><code class="language-javascript">// Exemplo real: rastrear listeners de eventos
const listeningMap = new WeakMap();
function adicionarListener(elemento, evento, callback) {
if (!listeningMap.has(elemento)) {
listeningMap.set(elemento, {});
}
const listeners = listeningMap.get(elemento);
if (!listeners[evento]) {
listeners[evento] = [];
}
listeners[evento].push(callback);
elemento.addEventListener(evento, callback);
}
function removerElement(elemento) {
const listeners = listeningMap.get(elemento);
if (listeners) {
Object.entries(listeners).forEach(([evento, callbacks]) => {
callbacks.forEach(cb => elemento.removeEventListener(evento, cb));
});
}
elemento.remove();
// WeakMap automaticamente limpa a entrada
}</code></pre>
<h2>WeakSet: Conjuntos com Referências Fracas</h2>
<p>WeakSet funciona como Set, mas mantém referências fracas aos seus elementos. Ideal para rastrear objetos sem impedir sua coleta de lixo. Assim como WeakMap, só aceita objetos, não é iterável e oferece apenas métodos <code>.add()</code>, <code>.has()</code> e <code>.delete()</code>.</p>
<pre><code class="language-javascript">// WeakSet para rastrear objetos autenticados
const usuariosAutenticados = new WeakSet();
class Sessao {
constructor(usuario) {
this.usuario = usuario;
usuariosAutenticados.add(usuario);
}
verificarAutenticacao(usuario) {
return usuariosAutenticados.has(usuario);
}
}
const user = { id: 1, nome: 'Ana' };
const sessao = new Sessao(user);
console.log(sessao.verificarAutenticacao(user)); // true</code></pre>
<h3>Comparação Prática: WeakSet vs Set</h3>
<p>WeakSet evita memory leaks ao não impedir coleta de lixo, enquanto Set mantém referências fortes. Use WeakSet quando precisar apenas verificar "se um objeto foi registrado", sem necessidade de iteração. Um exemplo real é rastrear instâncias já processadas em um ciclo de vida.</p>
<pre><code class="language-javascript">// Padrão: evitar reprocessamento de objetos
const processados = new WeakSet();
function processarObjeto(obj) {
if (processados.has(obj)) {
console.log('Já foi processado');
return;
}
console.log('Processando:', obj);
// Lógica pesada aqui...
processados.add(obj);
}
let objeto = { id: 1 };
processarObjeto(objeto); // Processando: { id: 1 }
processarObjeto(objeto); // Já foi processado
objeto = null; // Liberado da memória automaticamente</code></pre>
<h2>Boas Práticas em Produção</h2>
<p>Combine esses três recursos estrategicamente. Use <strong>Symbols</strong> para evitar colisões de chaves em bibliotecas compartilhadas ou quando trabalhar com plugins de terceiros. Use <strong>WeakMap</strong> para armazenar dados privados associados a instâncias, especialmente em frameworks como React (por exemplo, para rastrear componentes). Use <strong>WeakSet</strong> para rastrear membros de um grupo sem afetar garbage collection.</p>
<p>Evite criar aplicações complexas que dependem de iteração sobre WeakMap/WeakSet — se precisar iterar, use Map/Set normais. Não confunda Symbols com strings para segurança: symbols oferecem proteção contra acesso acidental, não contra ataques deliberados. Em produção, sempre teste memory leaks com ferramentas como Chrome DevTools para validar que WeakMap e WeakSet estão funcionando corretamente.</p>
<h2>Conclusão</h2>
<p>Symbols, WeakMap e WeakSet são ferramentas poderosas para escrever código robusto e eficiente. <strong>Symbols</strong> criam identificadores únicos e imutáveis, protegendo propriedades de objetos sem aparecer em enumerações. <strong>WeakMap</strong> associa dados a objetos sem impedir coleta de lixo, ideal para caching e dados privados ligados ao ciclo de vida. <strong>WeakSet</strong> rastreia objeto sem manter referências fortes, prevenindo memory leaks em padrões de validação e processamento.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol" target="_blank" rel="noopener noreferrer">MDN - Symbol</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap" target="_blank" rel="noopener noreferrer">MDN - WeakMap</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet" target="_blank" rel="noopener noreferrer">MDN - WeakSet</a></li>
<li><a href="https://javascript.info/weakmap-weakset" target="_blank" rel="noopener noreferrer">JavaScript.info - WeakMap and WeakSet</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS" target="_blank" rel="noopener noreferrer">You Don't Know JS - ES6 & Beyond</a></li>
</ul>