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:
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:
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:
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:
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:
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:
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:
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:
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: