Academic Block

WeakSet & WeakMap Get Certified

WeakMap and WeakSet are specialized collections that hold weak references to objects. Unlike regular Map and Set, they do not prevent their contents from being garbage-collected when nothing else points to those objects.

In this lesson you will learn the differences from their strong counterparts, the restrictions they impose, and the practical patterns they enable — private data, metadata, and tracking without memory leaks.

What Is a WeakMap?

A WeakMap stores key-value pairs where the keys must be objects. The references to those keys are weak, so the entry can be cleaned up automatically when the key object is no longer reachable elsewhere.

What this code does: Create a WeakMap and store a value against an object key. The key must be an object; primitives are not allowed.

const meta = new WeakMap();
const user = { name: "Alex" };
meta.set(user, { role: "admin" });
console.log(meta.get(user));
console.log(meta.has(user));

WeakMap Only Accepts Object Keys

Trying to use a string, number, or other primitive as a key throws a TypeError.

What this code does: WeakMap rejects non-object keys. The try/catch shows the error message when a string is used as a key.

const meta = new WeakMap();
try {
    meta.set("userId", { role: "admin" });
} catch (err) {
    console.log("Error:", err.message);
}

Basic WeakMap Methods

The available methods are set(), get(), has(), and delete(). There is no size, no iteration, and no clear().

What this code does: Demonstrate set, get, has, and delete. After deletion the key is no longer present.

const cache = new WeakMap();
const element = { id: "btn-1" };
cache.set(element, { clicks: 0 });
console.log(cache.get(element));
console.log(cache.has(element));
cache.delete(element);
console.log(cache.has(element));

No Size and No Iteration

Because entries can disappear at any time due to garbage collection, WeakMap deliberately does not expose size or allow looping.

What this code does: Attempting to read size or iterate is not supported. The example simply confirms that size is undefined.

const wm = new WeakMap();
const obj = {};
wm.set(obj, 1);
console.log(typeof wm.size); // undefined
console.log("size" in wm);   // false

Use Case: Private Instance Data

A classic pattern is to keep a WeakMap defined outside a class to store data that should be private to each instance, keyed by the instance itself.

What this code does: A classic use case: store private instance data in a WeakMap. The balance is hidden from the outside and cleaned up when the account object is garbage collected.

const privateData = new WeakMap();

class BankAccount {
    constructor(owner, balance) {
        this.owner = owner;
        privateData.set(this, { balance: balance });
    }
    getBalance() {
        return privateData.get(this).balance;
    }
    deposit(amount) {
        const data = privateData.get(this);
        data.balance += amount;
    }
}

const account = new BankAccount("Michael", 100);
account.deposit(50);
console.log(account.getBalance());
console.log(account.balance);

Notice that account.balance is undefined — the actual balance lives only inside privateData, accessible only through the class’s own methods.

Use Case: Attaching Metadata to Objects

A WeakMap is also useful for associating extra information with an object without modifying the object itself.

What this code does: Track per-object metadata (view counts) without preventing the product object from being garbage collected when it is no longer used.

const viewCounts = new WeakMap();

function trackView(item) {
    const currentCount = viewCounts.get(item) || 0;
    viewCounts.set(item, currentCount + 1);
    return viewCounts.get(item);
}

const productCard = { id: "P100" };
console.log(trackView(productCard));
console.log(trackView(productCard));
console.log(trackView(productCard));

What Is a WeakSet?

A WeakSet stores a collection of unique objects (not primitive values), similarly held weakly. It supports add(), has(), and delete().

What this code does: A WeakSet holds unique objects with weak references. add and has mark and check whether a page object has been visited.

const visitedPages = new WeakSet();
const page1 = { url: "/home" };
const page2 = { url: "/about" };
visitedPages.add(page1);
console.log(visitedPages.has(page1));
console.log(visitedPages.has(page2));

WeakSet Also Requires Objects

What this code does: WeakSet only accepts objects. Adding a string throws a TypeError.

const visitedPages = new WeakSet();
try {
    visitedPages.add("not an object");
} catch (err) {
    console.log("Error:", err.message);
}

Deleting From a WeakSet

What this code does: delete removes an object from the WeakSet. After deletion, has returns false for that user.

const flaggedUsers = new WeakSet();
const user = { name: "Guest" };
flaggedUsers.add(user);
console.log(flaggedUsers.has(user));
flaggedUsers.delete(user);
console.log(flaggedUsers.has(user));

Use Case: Marking Objects as Processed

A WeakSet is a natural fit for tracking which objects have already been handled, without needing to modify those objects with a flag property.

What this code does: Use a WeakSet to mark objects as already processed. Calling the function twice with the same order object detects the duplicate and skips reprocessing.

const processedOrders = new WeakSet();

function processOrder(order) {
    if (processedOrders.has(order)) {
        return "Order " + order.id + " was already processed.";
    }
    processedOrders.add(order);
    return "Processing order " + order.id + " now.";
}

const order1 = { id: "ORD-1" };
console.log(processOrder(order1));
console.log(processOrder(order1));

Map/Set vs. WeakMap/WeakSet

Feature Map / Set WeakMap / WeakSet
Allowed keys/values Any type Objects only
Prevents garbage collection? Yes (strong references) No (weak references)
Has a size property? Yes No
Iterable (for…of, forEach)? Yes No
Typical use case General-purpose collections Private data, metadata, object tracking

Practical Example

Let’s combine a WeakMap and a WeakSet to track login attempts for session objects and flag suspicious sessions after too many failures.

What this code does: Combine WeakMap (metadata) and WeakSet (flagging). Failed attempts are counted; when a threshold is reached the session is added to the flagged set.

const sessionMetadata = new WeakMap();
const flaggedSessions = new WeakSet();

function createSession(userId) {
    const session = { userId: userId };
    sessionMetadata.set(session, { attempts: 0 });
    return session;
}

function recordFailedAttempt(session) {
    const meta = sessionMetadata.get(session);
    meta.attempts++;
    if (meta.attempts >= 3) {
        flaggedSessions.add(session);
    }
}

const session = createSession("user_42");
recordFailedAttempt(session);
recordFailedAttempt(session);
recordFailedAttempt(session);
console.log(flaggedSessions.has(session));
console.log(sessionMetadata.get(session));

If session were ever discarded and no longer referenced anywhere else in the program, both its metadata entry and its flagged status would automatically become eligible for cleanup — no manual removal required.

Common Mistakes With WeakMap and WeakSet

  • Trying to use a string, number, or other primitive as a WeakMap key or WeakSet value, which throws a TypeError.
  • Expecting to loop over a WeakMap or WeakSet, or check its size, when neither feature is supported.
  • Using WeakMap/WeakSet when a regular Map/Set was actually needed, simply because “weak” sounds like a performance optimization rather than a specific memory-management tool.
  • Assuming entries disappear immediately once an object is no longer used elsewhere — garbage collection timing is not predictable or immediate.
  • Storing primitive identifiers (like a numeric ID) instead of the actual object reference, which defeats the purpose of using a weak collection in the first place.

Best Practices for WeakMap and WeakSet

  • Use WeakMap for storing private or auxiliary data tied to the lifetime of specific objects.
  • Use WeakSet for tracking membership or “has this been seen/processed” status for a group of objects.
  • Reach for a regular Map or Set when you need to iterate over entries, check the size, or use non-object keys.
  • Don’t rely on WeakMap/WeakSet for logic that must run at a predictable time — garbage collection isn’t something your code should depend on directly.
  • Keep the object being used as a key/value as the actual reference you care about, not a copy or a derived identifier.

Quick Summary

  • WeakMap stores key-value pairs where keys must be objects, held with weak references.
  • WeakSet stores a collection of unique objects, also held weakly.
  • Both support set()/add(), get() (WeakMap only), has(), and delete().
  • Neither supports iteration or a size property, since entries can disappear as objects get garbage collected.
  • Common use cases include private instance data, metadata tracking, and marking objects as already processed.
  • Use regular Map or Set instead when you need iteration, size checks, or non-object keys.

Try It Yourself

Modify the code below. Try creating a second product and tracking its view count separately, or resetting a product’s count with delete().

What this code does: Practice example: track views for a product, then delete the entry. Try a second product or reset a count, then click Test My Code.

const viewCounts = new WeakMap();

function trackView(item) {
    const currentCount = viewCounts.get(item) || 0;
    viewCounts.set(item, currentCount + 1);
    return viewCounts.get(item);
}

const productA = { id: "P200" };
console.log(trackView(productA));
console.log(trackView(productA));
viewCounts.delete(productA);
console.log(viewCounts.has(productA));
Tip: A simple way to decide: if you ever need to list, count, or loop over everything stored in the collection, you need a regular Map or Set. If you only ever need to look something up by a specific object, a weak collection is a good fit.

Understanding WeakMap and WeakSet is useful before moving on to memory management concepts, classes, and more advanced JavaScript topics.

🧪 Test Your JavaScript Code

Edit the code on the left and click “Run Code” to see the console output on the right.

📝 JavaScript Code
👁 Console Output

Click “Run Code” to see the output here.

Ctrl + Enter to run code Esc to close