demo · v143

WeakMap Counter

DOM elements make ideal WeakMap keys: when the element is removed, the entry can be garbage-collected automatically. WeakMap.prototype.getOrInsert — new in Chrome 143 — collapses the classic has + get + set 0 pattern into a single call. Click any card to increment its per-node counter. Remove cards and the WeakMap cleans itself up; a plain Map would leak them.

Probing WeakMap.prototype.getOrInsert…
Probing getOrInsertComputed…
Click a card to increment · × to remove
0 live nodes
0 total clicks
0 first-visit inserts
0 existing-key hits
// WeakMap: DOM elements as keys → GC-friendly per-node state
const clickCounts = new WeakMap();

cardEl.addEventListener('click', () => {
  // getOrInsert: returns existing value OR inserts the default and returns it
  const count = clickCounts.getOrInsert(cardEl, 0);
  clickCounts.set(cardEl, count + 1);

  // getOrInsertComputed: lazily create an object on first access
  const meta = metaMap.getOrInsertComputed(cardEl, (el) => ({
    id: el.dataset.id,
    createdAt: Date.now(),
    clicks: 0,
  }));
  meta.clicks++;
});

// When cardEl is removed from the DOM and no references remain,
// the WeakMap entry is eligible for garbage collection — no manual cleanup.
cardEl.remove();
// Before: every pattern needs has() + get() + set()
const clickCounts = new Map(); // ← Map, not WeakMap: elements never GC'd

cardEl.addEventListener('click', () => {
  // Three lines to do what getOrInsert does in one:
  if (!clickCounts.has(cardEl)) {
    clickCounts.set(cardEl, 0);
  }
  const count = clickCounts.get(cardEl);
  clickCounts.set(cardEl, count + 1);
});

// With Map, we must manually delete entries when nodes are removed,
// or the Map holds a strong reference that prevents GC.
cardEl.remove();
clickCounts.delete(cardEl); // ← easy to forget → memory leak

see also