WeakMap also works really well for that, because it means you don't add any extra properties or symbols to the object itself. Instead you store it in the WeakMap with the object as a key, and it'll still get garbage collected with the object as if you'd added it to the object. I've found it's occasionally useful when you're trying to get things from different frameworks to interact with each other, both of those frameworks want to do things like assigning extra fields or setting up proxies, and then they start conflicting.
Good point. I haven't seen an analysis of the tradeoffs of using WeakMap vs Symbol properties. It would be cool if someone knowledgeable did a write-up on that. I imagine that performance could swing either way depending on lots of subtle factors.