Symbols, WeakMap & WeakRef
The Problem With String Keys
Every property key on an object is either a string or a Symbol. You have only used strings so far. The problem with strings: they collide.
If two independent pieces of code both add a property called "id" to the same object, one silently overwrites the other. In small programs this is manageable. In libraries that touch objects they don't own, it is a serious bug waiting to happen.
String keys are a shared namespace. Anyone who knows the name can read or overwrite your property. Symbols solve this entirely.
Symbols — Guaranteed Unique Keys
Symbol() creates a value that is always unique — no two Symbols are ever equal, even if they have the same description:
The Symbol is the only key that can access that slot. Nobody else can accidentally read or overwrite it — because nobody else has that exact Symbol object.
Symbols Are Invisible to Normal Enumeration
Symbol keys are skipped by for...in, Object.keys(), and JSON.stringify() — they are genuinely hidden from casual inspection:
This invisibility is intentional. Symbol-keyed properties are metadata — they do not appear in logs, serialisation, or normal iteration unless you go looking for them specifically.
Well-Known Symbols — Hooking Into Language Behaviour
You already met Symbol.iterator in the previous lesson. JavaScript has a set of well-known Symbols that let you customise how built-in operations treat your objects:
Well-known Symbols are how you make custom classes behave naturally with operators, console.log, template literals, and the rest of the language — without monkey-patching anything.
Symbol.for — Shared Global Symbols
Symbol() always creates a new unique Symbol. Symbol.for(key) looks up a global registry — the same key always returns the same Symbol, even across different files:
WeakMap — Private Data Without Memory Leaks
A regular Map holds strong references to its keys — if you store an object as a key, the Map prevents that object from being garbage collected even if nothing else references it. WeakMap holds weak references: if the key object is no longer referenced anywhere else, it can be garbage collected and the WeakMap entry disappears automatically.
WeakMap keys must be objects (not primitives). You cannot iterate a WeakMap, get its size, or list its keys — by design. These restrictions are what allow the garbage collector to do its job.
WeakSet — Tracking Objects Without Owning Them
WeakSet is like Set but holds weak references. Useful for tracking which objects have been "seen" or "processed" without preventing their cleanup:
WeakRef — Holding Without Owning
WeakRef wraps an object in a weak reference — you can hold onto it without preventing garbage collection. Call .deref() to get the object back; if it has been collected, you get undefined:
Putting It Together — A Private Event System
Here is a realistic pattern that combines Symbols and WeakMap: a private event emitter where the internal state is completely hidden from outside code:
What You Have Learned
Symbols, WeakMap, WeakSet, and WeakRef are precision tools — you will not reach for them daily, but when you need them there is no substitute.
The key ideas:
Symbol()creates a guaranteed-unique key — two Symbols with the same description are never equal- Symbol keys are invisible to
for...in,Object.keys, andJSON.stringify— genuine metadata - Well-known Symbols (
Symbol.iterator,Symbol.toPrimitive,Symbol.toStringTag) let you hook into built-in language behaviour Symbol.for(key)uses a global registry — same key, same Symbol, across files- WeakMap stores private data keyed by object — entries disappear automatically when the key object is garbage collected
- WeakSet tracks objects without owning them — no iteration, no size, no leaks
- WeakRef holds an object without preventing collection — always guard
.deref()againstundefined
In the next lesson: Proxies & Reflect — intercept and redefine fundamental operations on any object. Property access, assignment, function calls, instanceof — every operation JavaScript performs on an object can be trapped and customised. The foundation of validation libraries, reactive frameworks, and ORMs.