Where it runs
1. The problem
In the last step you worked with Maps: a key points at a value. A Map holds on to its keys. As long as the Map exists, every key in it stays in memory too, even when the rest of your program no longer needs that key. Usually that is fine. Sometimes it becomes a slow memory leak: memory that gets taken and is never freed.
Say you want to attach a little data to objects that come and go. For example, each element on a page gets a count of how many times it was drawn. Or each incoming request gets an "already checked" mark. Put those in a normal Map with the object itself as the key, and the Map keeps every one of those objects in memory forever. The elements are removed from the page, the requests finish, and the Map still holds them. Your only defense is to remember to delete each entry by hand. Miss one and memory grows for as long as the program runs.
WeakMap and WeakSet solve this. In them a key can be forgotten on its own.
2. In plain words
Take one object from the code below: a page element node = { id: 1 }. You want to note that it was drawn 3 times, so you store { renders: 3 } in a WeakMap with node as the key.
Later the page removes the element, and no other part of the program refers to node anymore. At that point the engine is allowed to free node, and the entry node → { renders: 3 } goes away with it. You never wrote a line to remove the note. There is also no big list of all the noted elements that someone would have to clean up.
So the data stays attached to its object and disappears together with it, and there is no cleanup step for you to remember.
3. The idea
A WeakMap is similar to a Map: a key points at a value. There is one rule: the keys must be objects, and plain strings or numbers are not allowed. A WeakSet is similar to a Set: it stores a mark "this object is here". The rule is the same: only objects go in.
The word "weak" describes how the collection holds its keys. A normal Map keeps a key in memory just by holding it. A WeakMap does not. Here "in memory" means the JavaScript engine (the program that runs your code) still keeps the object. Garbage collection is the engine's own job of freeing the memory of any object that nothing refers to anymore. If the only thing that refers to an object is a WeakMap key, the engine may remove the object and quietly remove that entry along with it. You wrote no cleanup code: the entry left when the object did.
That rule has a price. An entry can disappear at any moment the engine decides to collect garbage. So a weak collection gives you no way to look at all of its contents. Weak collections cannot be looped over, and they have no size. You cannot walk through them in a loop, and you cannot ask how many entries they hold. You can only ask about an object you already have.
So there are only a few operations:
const meta = new WeakMap();
const node = { id: 1 }; // any object works as a key
meta.set(node, { renders: 3 }); // attach data to it
meta.get(node); // { renders: 3 }
meta.has(node); // true
meta.delete(node); // remove it early if you want
const seen = new WeakSet();
seen.add(node); // mark this object
seen.has(node); // true
When node is no longer used anywhere else, both the entry in meta and the mark in seen may disappear. You never call delete for that.
One honest note before you practice. Garbage collection runs on the engine's own schedule. You cannot force it to run, and a test cannot see it happen. So the exercise below does not try to prove that entries disappear. It trains the part you can check: choosing which of the four collections a situation needs.
4. What it costs
set, get, has and delete each take about one step, as in a Map or a Set. Memory is O(n), where n is the number of entries whose keys are still in use. The gain is what you do not pay for. Once a key object is not used anywhere else, its entry stops taking up your memory, and you wrote no code for that. A forgotten delete cannot leak here, because no delete is needed at all.
The price is in the limits. Keys must be objects, so you cannot use a user id string or a number as a key. There is no loop and no size, so a WeakMap does not fit when you need to list or count what is inside. In those cases go back to a plain Map or Set from the last two steps. The cleanup is then yours again.
6. Where this shows up
A cache (a stored result of a computation) uses the request or config object that produced the result as its key. The cache entry goes away with the object, and nobody has to clean it up. Private fields in a class library: a WeakMap at module level maps each instance to its hidden state, which nothing outside can reach. Marks on objects a processing pipeline has already handled, without keeping those objects in memory after the job. Libraries that attach their own bookkeeping to objects you pass them, for example page nodes (the elements a browser builds a page from). A plain Map would keep your objects in memory for the whole life of the library. When data belongs to an object and should live exactly as long as that object, WeakMap and WeakSet clean it up for you.
On LeetCode
LeetCode has no problem that needs a WeakMap or WeakSet, because its tests never measure memory. The skill from this lesson, picking the right one of four collections, is tested by the Map and Set problems in lessons 11, 12 and 18.
Your task (Tier 3)
This step has more reading than code. Read the rule, then complete pickCollection(scenario).
You get an object that describes a situation. Return the name of the right collection: "WeakMap", "WeakSet", "Map" or "Set".
- Input:
scenario, an object with three true/false flags:keysAreObjects(the keys are objects),storesValue(a value is stored under each key) andforgetWhenUnused(an entry should be forgotten on its own). - Return: one of
"WeakMap","WeakSet","Map","Set".
Steps:
- First decide whether a weak collection is allowed. It is allowed only when
keysAreObjectsis true ANDforgetWhenUnusedis true. - If weak is allowed: return
"WeakMap"whenstoresValueis true, otherwise"WeakSet". - If not: return
"Map"whenstoresValueis true, otherwise"Set".
Done when all tests pass:
- keys are objects, stores a value, wants auto-forget ->
"WeakMap" - keys are text, membership only, no auto-forget ->
"Set" - keys are objects, membership only, wants auto-forget ->
"WeakSet" - keys are text, stores a value, no auto-forget ->
"Map" - keys are objects, membership only, no auto-forget ->
"Set" - wants auto-forget but keys are text ->
"Map"(a weak collection cannot use text as a key, so the cleanup is yours)
Practice
pickCollection (Map / Set / WeakMap / WeakSet)
export function pickCollection(scenario) {
// Your code here. The task is described in the box above the editor.
}
Running as a guest
The tests run right here, no account needed. Your code is kept in this browser only. A free account keeps it on every device, marks the step done and shows where you are in the course.
Hint ladder
Stuck? Reveal one rung at a time, but try it yourself first.