javascript / typescript / performance / data-structures

Why I Reach for Map Over Object in JavaScript

Plain objects have prototype quirks and limited key types. Map handles dynamic collections more cleanly and eliminates a whole class of bugs.

2 min read
Cover image for Why I Reach for Map Over Object in JavaScript

Why I Reach for Map Over Object in JavaScript

I used to use plain objects for everything in JavaScript. Key value storage. Caches. Lookup tables. Configuration. It is what everyone does because it is what everyone learned first.

But objects have quirks. The prototype chain can interfere with your keys. If you store a key called toString or constructor, you get unexpected behavior. The iteration order is technically guaranteed now but nobody remembers when that changed. And you cannot use non-string keys at all.

Map fixes all of that. Keys can be anything. Functions, objects, symbols. There is no prototype pollution because Map does not inherit from Object.prototype. Iteration order is insertion order, consistently. The API is clean with get, set, has, and delete.

The performance difference matters too. Map handles frequent additions and deletions better than Object. V8 optimizes both, but Map has a more predictable memory profile when you are constantly adding and removing entries.

Here is the pattern I used to write:

JavaScript
const cache = {}; function getCached(key) { return cache[key]; } function setCached(key, value) { cache[key] = value; }

And here is what I write now:

JavaScript
const cache = new Map(); function getCached(key) { return cache.get(key); } function setCached(key, value) { cache.set(key, value); }

The second version is not much longer and it avoids the prototype problem entirely.

There are still cases where Object makes sense. If you need JSON serialization without a replacer, Object wins because Map serializes to an empty object by default. Configuration objects that you pass to libraries often need to be plain objects too. And for small static dictionaries, an object literal is fine.

For dynamic collections, caches, and anything where the keys are not known ahead of time, I reach for Map. It is one of those small changes that eliminates a whole class of bugs without adding complexity.