Prefer a Map to an object when keys are not strings, entries change often, or you need size and ordered iteration without inherited keys. It has set() (chainable), get(), has(), delete(), clear(), forEach(), keys(), values() and entries(); Object.fromEntries(map) turns it into an object, and ES2024 Map.groupBy() groups by any key. A WeakMap has only get(), set(), has(), delete() and the upserts (Upsert Methods); its keys are objects or (ES2023) non-registered symbols, and an entry vanishes once its key is unreachable.
const button = { id: 'buy' };
const clicks = new Map([['home', 3]]).set(button, 1).set(NaN, 0);
console.log(clicks.get(button), clicks.get({ id: 'buy' }), clicks.get(NaN), clicks.size);
console.log(Map.groupBy([1, 2, 3, 4, 5], (n) => (n % 2 ? 'odd' : 'even')));
const secrets = new WeakMap(); // per-instance private data
class Account {
constructor(balance) { secrets.set(this, { balance }); }
get balance() { return secrets.get(this).balance; }
}
console.log(new Account(50).balance, Object.keys(new Account(9)));1 undefined 0 3
Map(2) { 'odd' => [ 1, 3, 5 ], 'even' => [ 2, 4 ] }
50 []A WeakMap cannot be iterated, because a key list would reveal when the garbage collector ran. Use it for metadata about DOM nodes or objects you do not own. JSON.stringify(map) gives {}, so serialize [...map].