Skip to main content

JavaScript Map & Set

JavaScript WeakMap and WeakSet

Written by Published

WeakMap and WeakSet hold objects without preventing them being cleaned up.

A normal Map keeps its keys alive forever, which can leak memory.

A WeakMap lets the browser reclaim an object once nothing else refers to it.

Example

Example

javascript

const cache = new WeakMap();
const user = { name: "Ada" };

cache.set(user, "some cached data");

console.log(cache.get(user));
console.log(cache.has(user));

The output is the cached data then true.

How They Differ

Keys must be objects; primitives are not allowed.

They are not iterable, and have no size.

Entries disappear automatically when the key object is no longer used.

Syntax

Syntax

javascript

const map = new WeakMap();
map.set(objectKey, value);

Only get, set, has and delete are available.

Keys Must Be Objects

A string key throws immediately.

Example

Example

javascript

const map = new WeakMap();
let message;

try {
  map.set("a string", 1);
} catch (error) {
  message = "keys must be objects";
}

console.log(message);

A normal Map would have accepted it.

No size and No Looping

You cannot ask how many entries there are.

That is deliberate: the count could change at any moment.

Example

Example

javascript

const map = new WeakMap();
const key = {};
map.set(key, 1);

console.log(map.size === undefined ? "no size property" : map.size);
console.log(typeof map.forEach);

Both confirm there is no way to inspect the contents.

Attaching Private Data

A WeakMap can hold data about an object without touching the object itself.

Private class fields have largely replaced this pattern.

Example

Example

javascript

const secrets = new WeakMap();

class Person {
  constructor(name, secret) {
    this.name = name;
    secrets.set(this, secret);
  }
  reveal() {
    return secrets.get(this);
  }
}

const ada = new Person("Ada", "hidden value");

console.log(ada.reveal());
console.log(Object.keys(ada).join(","));

The secret never appears as a property of the object.

WeakSet

The same idea, holding objects rather than pairs.

Example

Example

javascript

const seen = new WeakSet();
const item = { id: 1 };

seen.add(item);

console.log(seen.has(item));
console.log(seen.has({ id: 1 }));

The second is false, because it is a different object.

When to Use Them

Use a WeakMap to attach data to objects you do not own.

For everything else, a normal Map is easier to work with.

Example

Example

javascript

const map = new Map();
const weak = new WeakMap();
const key = { id: 1 };

map.set(key, "a");
weak.set(key, "b");

console.log(map.size);
console.log(weak.get(key));

The Map can be counted and looped; the WeakMap cannot.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript WeakMap</title>
</head>
<body>

  <h1>WeakMap and WeakSet</h1>

  <p id="out"></p>

  <script>
    const secrets = new WeakMap();

    class Person {
      constructor(name, secret) {
        this.name = name;
        secrets.set(this, secret);
      }
      reveal() {
        return secrets.get(this);
      }
    }

    const ada = new Person("Ada", "kept outside the object");

    document.getElementById("out").innerHTML =
      "Name: " + ada.name +
      "<br>Own properties: " + Object.keys(ada).join(", ") +
      "<br>Secret: " + ada.reveal();
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try a string key:

Call secrets.set("x", 1) and see the error.

Important Points

  • WeakMap keys must be objects.
  • They are not iterable and have no size.
  • Entries vanish when the key object is no longer referenced.
  • Useful for attaching data to objects you do not own.
  • For ordinary work, a normal Map is easier.

Conclusion

Weak collections solve a memory problem rather than a convenience one.

You will meet them rarely, but knowing why they exist is worth it.

Private class fields have replaced their most common use.