Consider an implementation for a LinkedList
or a Tree
. You might not want to expose next
, last
, children
, or parent
as a property, but instead make it a property accessor that checks a static WeakMap
for the existence of such relationships. This way, your implementation allows the relationships to maintain weak connections.
HTML elements are a good way of explaining this. Let's say you partially implement an HTML element:
const HTMLElement = (() => {
const children = new WeakMap()
class Node {
constructor () {
children.set(this, [])
}
get children () {
return children.get(this)
}
appendChild (element) {
children.get(this).push(element)
return element
}
removeChild (element) {
const elements = children.get(this)
elements.splice(elements.indexOf(element), 1)
return element
}
}
return class HTMLElement extends Node {
constructor (tag) {
super()
this.tagName = tag.toUpperCase()
}
toString () {
return `<${this.tagName}>${children.get(this).join('')}</${this.tagName}>`
}
}
})()
{
const p = new HTMLElement('p')
p.appendChild(new HTMLElement('a'))
p.appendChild(new HTMLElement('span'))
console.log(`${p}`)
}
// a and span get GC'd when reference to p is lost
console.log(typeof p)
If children
was a Map
, you'd have a memory leak when the reference to p
is lost, because the others would still have strong references since HTMLElement
is still accessible.