I’ll produce this as a single HTML file with embedded styling and scripts, and I’ll make the snippets executable demos rather than static examples so each result tracks the code directly. When Should JS WeakMap Be Used?

When Should JS WeakMap Be Used?

An interactive memory-reference demo: remove DOM nodes, compare strong references with weak keys, and practice the WeakMap API.

1. Removing a DOM node does not erase a live variable reference

Code:
var eleImage = demo.root.querySelector('[data-demo-img]');
eleImage.remove();

setTimeout(() => {
  demo.root.append(eleImage);
  demo.write('The same DOM node came back because eleImage still references it.');
}, 1200);
Result:
Ready.

2. Setting your variable to null removes that handle

Code:
var eleImage = demo.root.querySelector('[data-demo-img]');
eleImage.remove();
eleImage = null;

setTimeout(() => {
  if (eleImage) {
    demo.root.append(eleImage);
  }

  demo.write('eleImage is null, so this code has no node to append back.');
}, 1200);
Result:
Ready.

3. Another strong reference can still keep the removed node alive

Code:
var eleImage = demo.root.querySelector('[data-demo-img]');
var storage = {
  arrDom: [eleImage, eleImage.outerHTML]
};

eleImage.remove();
eleImage = null;

setTimeout(() => {
  demo.root.append(storage.arrDom[0]);
  demo.write('storage.arrDom[0] still points at the removed node.');
}, 1200);
Result:
Ready.

4. Manual cleanup means clearing every strong reference

Code:
var eleImage = demo.root.querySelector('[data-demo-img]');
var storage = {
  arrDom: [eleImage, eleImage.outerHTML]
};

eleImage.remove();
eleImage = null;
storage.arrDom[0] = null;

setTimeout(() => {
  if (storage.arrDom[0]) {
    demo.root.append(storage.arrDom[0]);
  }

  demo.write('The array reference was cleared, so nothing is restored.');
}, 1200);
Result:
Ready.

5. Map keeps object keys strongly and lets you enumerate them

Code:
var eleImage = demo.root.querySelector('[data-demo-img]');
var storeMap = new Map();

storeMap.set(eleImage, eleImage.outerHTML);
eleImage.remove();
eleImage = null;

setTimeout(() => {
  demo.root.append(storeMap.keys().next().value);
  demo.write('Map.keys() recovered the original DOM key.');
}, 1200);
Result:
Ready.

6. WeakMap stores metadata without an enumerable recovery path

Code:
var eleImage = demo.root.querySelector('[data-demo-img]');
var storeMap = new WeakMap();

storeMap.set(eleImage, eleImage.outerHTML);
eleImage.remove();
eleImage = null;

setTimeout(() => {
  demo.write('WeakMap has no keys() method: ' + String(storeMap.keys));
  demo.write('When the key is unreachable, its cached value can be collected.');
}, 1200);
Result:
Ready.

7. WeakMap has set, get, has, and delete

Code:
const key = {};
const myWm = new WeakMap();

myWm.set(key, 'cached value');
demo.write('After set, has key: ' + myWm.has(key));
demo.write('get(key): ' + myWm.get(key));

myWm.delete(key);
demo.write('After delete, has key: ' + myWm.has(key));
Result:
Ready.

8. WeakMap keys must be objects

Code:
const myWm = new WeakMap();

myWm.set([], 1);
myWm.set(new Date(), 'date metadata');
myWm.set(() => {}, 'function metadata');
myWm.set(document.createElement('section'), 'element metadata');

demo.write('Object keys were accepted.');

try {
  myWm.set('css new world', true);
} catch (error) {
  demo.write(error.name + ': ' + error.message);
}
Result:
Ready.

9. Non-enumerable keys can model private object data

Code:
const privateData = new WeakMap();

class Fish {
  constructor(name) {
    privateData.set(this, {
      fishbone: ['grass carp', 'crucian carp', 'black carp', 'common carp', 'silver carp']
    });

    this.name = name;
  }

  isBone() {
    return privateData.get(this).fishbone.includes(this.name);
  }
}

const fish = new Fish(demo.input.value);

demo.write('fish.name: ' + fish.name);
demo.write('fish.fishbone: ' + String(fish.fishbone));
demo.write('Object.keys(fish): ' + Object.keys(fish).join(', '));
demo.write('privateData.keys: ' + String(privateData.keys));
demo.write('has intermuscular bones: ' + fish.isBone());
Result:
Ready.