简体   繁体   中英

How can a weak map be implemented in ES5?

There is another question that asks the same, but I cannot grok the accepted answer.

The library in question appears to use Object.defineProperty to add a reference to the object to be stored (albeit indirectly via another object).

But... surely that would then mean the object cannot be garbage collected because of this link?

What am I missing?

Is it really possible to create an object and store it somewhere without maintaining a reference noticeable by the garbage collector? (Prior to ES2015)

The accepted answer:

It took me a while to grok the code, but then it hit me: the key itself is used to store a reference to the value.

For example, several layers into set it does

defProp(obj, globalID, { value: store }); where defProp has been defined to be Object.defineProperty, obj is the key, globalID is a guid and store is a storage object that contains the value.

Then down in get it looks up the value with

obj[globalID];

This is very clever. The WeakMap doesn't actually contain a reference to anything (weak or otherwise)-- it just sets up a policy of where to secretly store the value. The use of Object.defineProperty means that you won't accidentally discover the value storage-- you have to know the magic guid to look it up.

Since the key directly refers to the value (and the WeakMap doesn't refer to it), when all references to the key are gone, it gets GCed like normal.

The library in question .

surely that would then mean the object cannot be garbage collected because of this link?

Yes.

What am I missing?

Nothing. Maybe that this is exactly the desired behaviour.

As the answer explains, " the WeakMap doesn't actually contain a reference to anything (weak or otherwise) " and " when all references to the key are gone, it gets GCed like normal. "

The code in the library in question is convoluted. But based on another, clearer, WeakMap implementation I have the following...

A WeakMap holds a weak reference to both the key and the value associated with it. This means the WeakMap does not affect in any way the garbage collection of with the key object or the value object.

On way to achieve this in ES5 is to add a (hidden if you want) property to the key used when it is "added" to the map and then do nothing else (ie do not add the key to an array or indeed do anything with it). In that way nothing refers to the key other than itself.

AFAICT WeakMap has a limited API for this reason. You cannot, for example, enumerate the items in a WeakMap because it holds no references to its contents!

Note that the key in a WeakMap cannot be a primitive (string, number, undefined, null, Symbol, boolean).

When using has or get , you can simply look for the secret property on the object supplied as the key.

If it is present, the WeakMap "contains" or "has" it; otherwise it doesn't.

For get , the secret property could contain a reference to the value associated with the key object, again, with no reference from WeakMap to the key object or the value object.

I think.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM