6

There is already some questions about map and weak maps, like this: What's the difference between ES6 Map and WeakMap? but I would like to ask in which situation should I favor the use of these data structures? Or what should I take in consideration when I favor one over the others?

Examples of the data structures from:https://github.com/lukehoban/es6features

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set

Bonus. Which of the above data structures will produce the same/similar result of doing: let hash = object.create(null); hash[index] = something;

Community
  • 1
  • 1
ncubica
  • 7,276
  • 7
  • 50
  • 67
  • 7
    *"Bonus"* Ask **one** question per question. – T.J. Crowder Sep 22 '15 at 07:13
  • 1
    [Relevant question](http://stackoverflow.com/questions/15604168/whats-the-difference-between-es6-map-and-weakmap) on Maps alone. Especially the IIFE example – CodingIntrigue Sep 22 '15 at 10:19
  • 2
    Related: [What are the actual uses of ES6 WeakMap?](http://stackoverflow.com/q/29413222/218196) – Felix Kling Sep 22 '15 at 13:48
  • … and also [ECMAScript 6: what is WeakSet for?](http://stackoverflow.com/q/30556078/1048572). I'm really inclined to close as a duplicate. – Bergi Sep 22 '15 at 17:31
  • This is not only about WeakSet, is about when favor one over the others, is not duplicated it ... @Bergi – ncubica Sep 22 '15 at 18:11
  • @ncubica: Well, you certainly know when to use a map vs a set? Now for what the use cases of making it weak are, those are clearly answered in the already existing posts. Only that you've asked two questions (one about maps, the other about sets), plus that bonus thingie, in one post, so it is hard to find an exact dupe. – Bergi Sep 22 '15 at 20:39

1 Answers1

14

This is covered in §23.3 of the specification:

If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap.

So the entries in a weak map, if their keys aren't referenced by anything else, will be reclaimed by garbage collection at some point.

In contrast, a Map holds a strong reference to its keys, preventing them from being garbage-collected if the map is the only thing referencing them.

MDN puts it like this:

The key in a WeakMap is held weakly. What this means is that, if there are no other strong references to the key, then the entire entry will be removed from the WeakMap by the garbage collector.

And WeakSet does the same.

...in which situation should I favor the use of this data structures?

Any situation where you don't want the fact you have a map/set using a key to prevent that key from being garbage-collected. Here are some examples:

  1. Having instance-specific information which is truly private to the instance, which looks like this: (Note: This example is from 2015, well before private fields were an option. Here in 2021, I'd use private fields for this.)

    let Thing = (() => {
        var privateData = new WeakMap();
    
        class Thing {
            constructor() {
                privateData[this] = {
                    foo: "some value"
                };
            }
    
            doSomething() {
                console.log(privateData[this].foo);
            }
        }
    
        return Thing;
    })();
    

    There's no way for code outside that scoping function to access the data in privateData. That data is keyed by the instance itself. You wouldn't do that without a WeakMap because it would be a memory leak, your Thing instances would never be cleaned up. But WeakMap only holds weak references, and so if your code using a Thing instance is done with it and releases its reference to the instance, the WeakMap doesn't prevent the instance from being garbage-collected; instead, the entry keyed by the instance is removed from the map.

  2. Holding information for objects you don't control. Suppose you get an object from some API and you need to remember some additional information about that object. You could add properties to the object itself (if it's not sealed), but adding properties to objets outside of your control is just asking for trouble. Instead, you can use a WeakMap keyed by the object to store your extra information.

  3. One use case for WeakSet is tracking or branding: Suppose that before "using" an object, you need to know whether that object has ever been "used" in the past, but without storing that as a flag on the object (perhaps because if it's a flag on the object, other code can see it [though you could use a private field to prevent that]; or because it's not your object [so private fields wouldn't help]). For instance, this might be some kind of single-use access token. A WeakSet is a simple way to do that without forcing the object to stay in memory.

Which of the above data structures will produce the same/similar result of doing: let hash = Object.create(null); hash[index] = something;

That would be nearest to Map, because the string index (the property name) will be held by a strong reference in the object (it and its associated property will not be reclaimed if nothing else references it).

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 3
    I've been studying ES6/TypeScript this week and this must be the 30th time I've come across and benefited from an answer of yours, it's gotten to the point where I now expect the accepted answer to be yours. Thank you for putting in so much time and effort to help this community and other developers. – LogicalBranch Apr 26 '19 at 11:40
  • 1
    @LogicalBranch - Gosh, thanks! I really appreciate your taking the time to say that. :-) – T.J. Crowder Apr 26 '19 at 12:24