TypeScript / JavaScript - Will this WeakMap 'hack' work as I intend?

100 views Asked by At

Normally, if I want to keep an array full of all created instances of a class, I keep a reference to each instance in my array, thus keeping the instances from being garbage collected when the instances are no longer referenced elsewhere.

Is this a meaningful way to utilize a WeakMap for maintaining a way of iterating all my still-relevant instances, while not keeping them from being garbage collected?

const indexMap = new Map<number, number[]>()
const wmap = new WeakMap<number[], Person>()
let nextIndex = 0

class Person {
  i: number
  constructor() {
    this.i = nextIndex++
    const id = [this.i]
    indexMap.set(this.i, id)
    wmap.set(id, this)
  }
  destroy() {
    indexMap.delete(this.i)
  }
}

// create 3 instances
new Person()
new Person()
new Person()

// iterate instances
for (const id of indexMap.values()) {
  console.log(wmap.get(id))
}

I'm thinking, since the Person instances are not used as keys in the WeakMap, it might not work, but I'm not sure if I'm understanding it correctly, even after reading bunches about it and the MDN docs several times. I'm also not sure how to actually test if it works.

If anyone can explain or just link to something good I can read, that'd be awesome.

And if you think it should work, also suggest a way for me actually to verify that it's working. How do I test in my code whether the objects exist without referencing them? haha :)

1

There are 1 answers

0
Bergi On

No, this will not work. The keys in your wmap are still strongly referenced from the indexMap, keeping the Person instances alive until you destroy() them. But that could be achieved much easier:

const map = new Map<number, Person>()
let nextIndex = 0

class Person {
  i: number
  constructor() {
    this.i = nextIndex++
    map.set(this.i, this)
  }
  destroy() {
    map.delete(this.i)
  }
}

// create 3 instances
new Person()
new Person()
new Person()

// iterate instances
for (const person of map.values()) {
  console.log(person)
}