Back to JavaScript
JavaScript
easy
mid

What is the difference between Map and a plain Object in JavaScript?

Object: string/symbol keys, prototype chain (collisions like `__proto__`), no insertion order guarantee for integer-like keys, JSON-friendly. Map: any key (including objects, NaN, null), preserves insertion order, has `.size`, no prototype chain. Use Map when keys are non-strings, you need size, or iteration order matters; object for JSON-shaped data.

3 min read·~6 min to think through

Key differences

ObjectMap
Key typesString, SymbolAny (objects, NaN, null, primitives)
Prototype chainYes (collision hazards)No
Insertion orderMostly preserved; integer-like keys sortStrictly preserved
SizeObject.keys(o).length (O(n))map.size (O(1))
Iterationfor..in, Object.keys/entriesfor..of, .entries(), .forEach
Spec performanceOptimized for fixed shapesOptimized for frequent add/remove
JSONNative (JSON.stringify)Custom serialization needed

Object pitfalls

js
const o = {};
o["__proto__"] = "x";       // doesn't set a string key; touches prototype
o.constructor = "y";        // shadow built-in property

Mitigate with Object.create(null):

js
const safe = Object.create(null);
safe.__proto__ = "x";       // now just a regular string key

Map advantages

js
const m = new Map();
m.set({ id: 1 }, "alice");
m.set(NaN, "weird");
m.size;                     // 2
m.get(NaN);                 // "weird" (Map treats NaN consistently)
  • Object keys store user-by-object: no stringification.
  • Iteration order is insertion order, strictly.
  • size is O(1).
  • Frequent add/remove is faster than delete obj[k] (which can deoptimize shape).

When to use which

NeedUse
JSON-friendly dataObject
Small fixed shape (3-5 known keys)Object
Configurable / dynamic keys, especially non-stringMap
Frequent add/removeMap
Need iteration in insertion orderMap
Need .sizeMap
Cache keyed on objects (no GC)Map; WeakMap if you want GC

WeakMap

Like Map but keys are objects only, weakly held. When the key object is GC'd, the entry vanishes — great for "private state per object" patterns and memoization keyed on object identity.

Performance reality

For small fixed-shape objects (records), object literals are faster than Maps thanks to V8's hidden-class optimization. For dynamic, keyed-by-anything collections that change a lot, Map wins.

Serialization

js
const m = new Map([[1, "a"], [2, "b"]]);
JSON.stringify(m);             // "{}" — doesn't work
JSON.stringify([...m]);        // "[[1,"a"],[2,"b"]]"
JSON.stringify(Object.fromEntries(m));    // "{\"1\":\"a\",\"2\":\"b\"}"

Map needs help to serialize.

Iteration

js
for (const [k, v] of m) ...
m.forEach((v, k) => ...);

Plus m.keys(), m.values(), m.entries().

Interview framing

"Object: string/symbol keys, prototype chain (collision hazards like __proto__), good for fixed-shape data and JSON. Map: any keys including objects, no prototype chain, preserves insertion order strictly, has O(1) .size, and is faster for frequent add/remove. Use Object for records and JSON. Use Map when keys can be objects, you need ordered iteration, you'll add/remove a lot, or you need .size. WeakMap for object-keyed entries that should die with the key. Object.create(null) if you want object semantics but no prototype chain."

Follow-up questions

  • Why is Object.create(null) safer than {}?
  • When is WeakMap the right choice?
  • How would you serialize a Map?

Common mistakes

  • Object keys colliding with prototype methods.
  • Trusting Object key order with integer-like keys.
  • Trying to use objects as object-keys (they all stringify to '[object Object]').

Performance considerations

  • Object literals optimize for stable shape; Map for dynamic shape. Pick by shape, not just feature.

Edge cases

  • NaN as Map key works; in object stringifies.
  • Integer-like string keys ordered numerically in objects.
  • WeakMap can't iterate.

Real-world examples

  • Caches (Map), records (Object), private state per instance (WeakMap), Redux state (Object).

Senior engineer discussion

Seniors pick Map for dynamic key shapes and Object for records; they know about WeakMap for memory-friendly per-object metadata, and reach for Object.create(null) when using objects as bare key-value stores.

Related questions