Skip to Content
Course content

53: WeakMap and WeakSet

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're running a high-end hotel. When a guest checks in, you give them a physical key card (an object). To keep things organized, you maintain a private ledger behind the front desk. In this ledger, you don't write the guest's name—which could change or be shared—but you index your notes by that specific key card. You might note that "Key Card #402 prefers extra towels" or "Key Card #402 is a VIP."

Now, here is the magic part: the moment that guest checks out and throws their key card into the trash, you don't want to spend your time manually scrubbing your ledger to find every mention of that card. In a perfect world, the ledger entries tied to that card would simply evaporate the moment the card ceased to exist. That's exactly how WeakMap and WeakSet work in JavaScript.

The Memory Leak Trap

If you've used a standard Map, you know it holds a "strong" reference to its keys. If you use a DOM element as a key in a Map, that element will never be garbage collected as long as the Map exists, even if you remove the element from the page. I've seen plenty of junior devs accidentally create massive memory leaks this way because they forgot to manually map.delete(element).

A WeakMap solves this. It holds a "weak" reference. If there are no other references to the object used as a key, the JavaScript engine says, "Okay, nobody is using this object anymore," and it wipes the entry from the WeakMap automatically. It's a massive relief for memory management.

// Standard Map (Strong)
let user = { name: "Alice" };
let userMetadata = new Map();
userMetadata.set(user, "Premium Member");

user = null; // The object { name: "Alice" } is still in the Map! Memory is held.

// WeakMap (Weak)
let user2 = { name: "Bob" };
let privateData = new WeakMap();
privateData.set(user2, "Secret Note");

user2 = null; // The object { name: "Bob" } is now eligible for garbage collection.
// The entry in privateData will disappear automatically.

Storing Metadata Without Pollution

One of my favorite ways to use WeakMap is to associate data with an object that isn't yours to modify. Say you're using a third-party library that gives you a DOM element, and you want to track some internal state for that element without adding properties directly to it (which is generally a bad practice called "polluting" the object).

By using a WeakMap, you can keep your state separate. If the library deletes the element from the DOM, your state is cleaned up automatically. No cleanup functions, no manual null-ing out.

const elementState = new WeakMap();

function trackClickCount(el) {
    let count = elementState.get(el) || 0;
    elementState.set(el, count + 1);
    console.log(`Element clicked ${count + 1} times`);
}

const btn = document.querySelector('#myButton');
trackClickCount(btn); // 1
trackClickCount(btn); // 2

When to Reach for a WeakSet

A WeakSet is essentially the same concept, but for a set of values rather than key-value pairs. Since the keys in a WeakMap must be objects, the values in a WeakSet must also be objects. You can't put a string or a number in here.

I usually use WeakSet when I need to "tag" objects. For example, if you have a complex recursive function and you want to keep track of which objects you've already processed to avoid infinite loops, but you don't want to permanently modify those objects with a processed: true property.

Keep in mind: because they are "weak," WeakMap and WeakSet are not enumerable. You can't loop over them, you can't ask for their size, and you can't clear them all at once. You can only check if a specific object exists or get/set a value for a specific object. If you need to iterate, you have to stick with the standard Map or Set.




📋 Practical Task

Exercise: Building a DOM Element Permission Tracker

You are building a dashboard where some UI elements (buttons, inputs) are restricted based on user permissions. However, you cannot modify the DOM elements directly because they are generated by a legacy library.

Your Goal: Create a system that tracks whether a DOM element is "locked" or "unlocked" without adding properties to the element itself.

  • Create a WeakMap called permissionsMap.
  • Write a function setLockStatus(element, isLocked) that stores the boolean status in the map.
  • Write a function isElementLocked(element) that returns the status. If the element hasn't been tracked yet, it should return false (unlocked by default).
  • Test it by creating a dummy object (representing a DOM element), locking it, checking the status, and then nullifying the object to ensure the logic holds.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.