Map vs object
Many people assume that a Map and a plain object {} are almost the same thing, but there are substantial differences between them. An Object is a general purpose data structure for storing properties whose keys are strings or symbols, while a Map is a specialized collection for storing "key to value" pairs with keys of any type and preserved insertion order.
Theory
TL;DR
- Object keys are strings and symbols only,
Mapkeys are any values. - A
Mapalways returns elements in insertion order, an object sorts integer like keys. - Size:
Object.keys(obj).lengthversus a plainmap.size. - A
Mapis directly iterable withfor...of, an object is not. - A
Mapis faster under frequent inserts and deletes. - A
Mapdoes not inherit fromObject.prototype, so there are no clashes withtoStringorhasOwnProperty. - Conversion works both ways:
new Map(Object.entries(obj))andObject.fromEntries(map).
Quick example
const obj = {};
const map = new Map();
const keyObj = { id: 1 };
obj[keyObj] = 'object value';
map.set(keyObj, 'map value');
console.log(obj); // { "[object Object]": "object value" }
console.log(map.get(keyObj)); // "map value"In the object the key turned into the string "[object Object]", while in the Map it stayed a real object. If we added a second object as a key, in obj it would simply overwrite the first entry, because the resulting string would be identical.
Key types
| Feature | Object | Map |
|---|---|---|
| Keys | Strings or symbols only | Any type (strings, numbers, objects, functions and so on) |
This is the most important practical difference: only a Map lets you use an object or a function as a key and thereby attach data to a specific instance.
Order, size and iteration
Key order.
| Feature | Object | Map |
|---|---|---|
| Key order | Partly guaranteed (ES6 and later) | Always preserved |
A Map always returns elements in insertion order, while an object behaves differently with numeric keys:
const obj = { 2: 'b', 1: 'a' };
console.log(Object.keys(obj)); // ["1", "2"] (numbers are sorted ascending)const map = new Map([[2, 'b'], [1, 'a']]);
console.log([...map.keys()]); // [2, 1] (order is preserved)Size.
| Feature | Object | Map |
|---|---|---|
| Size | Object.keys(obj).length | map.size |
const map = new Map([['a', 1], ['b', 2]]);
console.log(map.size); // 2The difference is not only convenience: Object.keys() builds an intermediate array, while size is just reading a counter.
Iterability.
| Feature | Object | Map |
|---|---|---|
| Iterated directly | No | Yes |
const map = new Map([['x', 10], ['y', 20]]);
for (const [key, value] of map) {
console.log(key, value);
}
// x 10
// y 20For an object you have to call Object.keys(), Object.entries() and similar methods.
Performance and prototype
| Feature | Object | Map |
|---|---|---|
| Frequent inserts and deletes | Slower | Faster |
| Iterating over elements | Awkward | Convenient with for...of |
A Map is optimized exactly for frequent additions, deletions and traversal, whereas engines optimize objects for a stable "shape" with a known set of fields.
| Feature | Object | Map |
|---|---|---|
Inherits from Object.prototype | Yes | No |
Can clash with methods (toString, hasOwnProperty) | Yes | No |
A Map carries no "junk" in the form of built in methods, so any key is safe to use. In an object a key such as "hasOwnProperty" or "__proto__" can break your checks.
Converting between them
const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));
console.log(map); // Map(2) { 'a' => 1, 'b' => 2 }
const backToObj = Object.fromEntries(map);
console.log(backToObj); // { a: 1, b: 2 }Object.entries() and Object.fromEntries() make conversion in both directions easy. This is also how you serialize a Map, since JSON.stringify(map) on its own yields {}.
What to use and when
| Use | When |
|---|---|
Object | a data structure with fixed properties (a user model, for instance) |
Map | dynamic keys, keys of any type, caches, frequent add and delete operations |
In short:
| Feature | Object | Map |
|---|---|---|
| Key types | string or symbol | any type |
| Key order | partly ordered | preserved |
| Size | counted manually | .size |
| Iterability | via Object.keys() | directly (for...of) |
| Performance | lower | higher |
| Use case | static data | dynamic collections |
Common mistakes
- Using an object as a key of a plain object. The key silently becomes the string
"[object Object]"and all objects collapse into a single entry. - Relying on the order of numeric object keys. Integer like keys are always sorted ascending, regardless of insertion order.
- Writing
map.lengthormap['key']. The first isundefined, the second creates a property outside the collection; the correct forms aremap.sizeandmap.get('key'). - Serializing a
Mapdirectly.JSON.stringify(map)returns{}, you needObject.fromEntries(map)or an array from[...map]first. - Reaching for a
Mapeverywhere "because it is faster". For a small fixed model an object is more convenient: destructuring, shorthand syntax, native JSON support. - Forgetting that a
Mapholds keys strongly. Object keys will not leave memory while theMapitself is alive; for weak references there isWeakMap.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.