1

Example with "nulling" value. Why does the element still exist in the WeakMap collection in this case?

let weakMap = new WeakMap();
let obj = {name: 'Ivan'};
//adding some new element
weakMap.set({}, obj);
obj = null;
console.log(weakMap);
console.log(weakMap.get({}));

Whole collection

enter image description here

One element

enter image description here

Example with "nulling" key:

enter image description here

What's going on here? What does it come from? The garbage collector does not have time to clean up everything or what?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Ivan
  • 478
  • 2
  • 13
  • "*The garbage collector does not have time to clean up everything or what?*" - precisely. What you saw is what one will get when the unreachable objects have not yet been collected. – Bergi Jun 17 '22 at 00:04
  • @Bergi It turns out that...: 1. When JS working with the entire collection, the entire collection is fully displayed. The reason of that behaviour is the GC doesn't have time to clear up deleted elements, values etc. 2. And when JS working with a separate property, there's a search for this property. If there is no link to it, GC immediately deletes what necessary. Do I understand correctly? – Ivan Jun 17 '22 at 11:17
  • By "*there's a search for this property*", you mean the code from your "*One element*" screenshot? No, you're getting `undefined` there because you did search for a different object than the one you used as a key for `obj` (as explained below by pilchard). If you did `console.log(weakMap)` and inspect its internals, you would again see that the key-value pair you did store is still not garbage-collected. – Bergi Jun 17 '22 at 14:16
  • @Bergi no, I got it. I've already tried with **one** object, not with 2 different objects. But it seems to me that my guess is not right. It looks like JS or browser have different algorithms for working with 1 element and with the whole "weak" collection. Working with the whole collection is buggy) – Ivan Jun 17 '22 at 14:34

1 Answers1

2

First of all weakMap.set({}, obj); and weakMap.get({}); will never refer to the same element in the WeakMap because they are separate, anonymous object literals. In order for the WeakMap to be useful you need to store a reference to the object to be used as key1.

let weakMap = new WeakMap();
let obj = {name: 'Ivan'};

weakMap.set({}, obj);
console.log('has anonymous key:', weakMap.has({}));
console.log(weakMap.get({}));

let key = {};
weakMap.set(key, obj);
console.log('has assigned key:', weakMap.has(key));
console.log(weakMap.get(key));

Secondly, it is the key that is weakly referenced in the WeakMap, not the value, so setting the value to null will have no effect on the WeakMap. Instead you need to 'null' the key2 (another reason you need a stored reference to it).

let weakMap = new WeakMap();
let obj = { name: 'Ivan' };

let key = {};
weakMap.set(key, obj);

console.log(weakMap);

key = null;

// no good way to indicate this, but debugging in the console will reveal an empty WeakMap pending garbage collection
console.log(weakMap);

1 Your example using an unreachable object as key will disappear from the WeakMap on garbage collection, but not because you set obj=null but because the only reference to the object exists in the WeakMap.

2 There is no good way to demonstrate the behaviour of the second snippet because, per the documentation, '... a WeakMap doesn't allow observing the liveness of its keys, its keys are not enumerable.' Nonetheless, debugging in the console will reveal the behaviour, though awkwardly given the variety of ways different browsers treat objects in the console, ie. chrome's live objects.

pilchard
  • 12,414
  • 5
  • 11
  • 23
  • 1
    "*There is no good way to demonstrate the behaviour*" - when testing in the console, there are [various ways](https://stackoverflow.com/q/13950394/1048572) to force GC via the devtools – Bergi Jun 17 '22 at 00:07
  • @bergi I meant within the SO snippet itself, specific devtools advice seemed out of scope for the question. – pilchard Jun 17 '22 at 07:55
  • @pilchard I don't get it. You've written that _"key is weakly referenced in the WeakMap, not the value"_, but...I guess if I'm nulling the value, it should be `null`. Value doesn't have to stay the same as it was before. If I'm right about this, then why does the value in my example remain the same after nulling? What's the reason for this behaviour? Here is my [example](https://jsfiddle.net/z1rLg50t/1/) – Ivan Jun 17 '22 at 16:21
  • 2
    No, because nulling one variable that holds a reference to a value doesn't change all other variables referencing that value. `a = 1; b = a; a = null; b === 1;` just because you've changed the value assigned to `a` doesn't have any effect on the value assigned to `b` and the same is true of the value stored in the weakmap. Once it's assigned it knows nothing about any other variables also referencing the same object. – pilchard Jun 17 '22 at 17:04