JavaScript Map Object: Complete Guide

Learn the JavaScript Map object: a key-value collection that accepts any type as a key, preserves insertion order, and outperforms plain objects for frequent data operations.

6 min read

A Map is a built-in JavaScript collection that stores key-value pairs, similar to a plain object, but with important advantages: keys can be any type (not just strings), insertion order is guaranteed, and it is optimized for frequent additions and removals.

You create a Map with the new Map() constructor and interact with it through dedicated methods rather than dot or bracket notation.

Creating a Map and Basic Operations

An empty Map starts out with no entries, and you add to it with set() instead of assigning properties directly:

javascriptjavascript
const map = new Map();
 
map.set("name", "Alex");       // Add an entry
map.set("role", "admin");
 
console.log(map.get("name"));  // "Alex"
console.log(map.has("role"));  // true
console.log(map.size);         // 2

The same map object supports removing a single entry or clearing everything at once, and size updates automatically either way:

javascriptjavascript
map.delete("role");            // Remove an entry
console.log(map.has("role"));  // false
console.log(map.size);         // 1
 
map.clear();                   // Remove everything
console.log(map.size);         // 0
MethodDescription
map.set(key, value)Adds or updates an entry. Returns the map (chainable).
map.get(key)Returns the value for the key, or undefined if not found.
map.has(key)Returns true if the key exists.
map.delete(key)Removes the entry. Returns true if it existed.
map.clear()Removes all entries.
map.sizeThe number of entries (property, not a method).

Keys Can Be Any Type

This is the feature that sets Map apart from plain objects. You can use objects, functions, numbers, and even NaN as keys:

javascriptjavascript
const cache = new Map();
const userObj = { id: 1 };
const fetchFn = () => "data";
 
cache.set(userObj, { name: "Taylor" });
cache.set(fetchFn, "cached result");
cache.set(42, "the answer");
 
console.log(cache.get(userObj)); // { name: "Taylor" }
console.log(cache.get(fetchFn)); // "cached result"

Keys are compared by identity for objects and by SameValueZero for primitives. This means NaN works as a key even though NaN !== NaN:

javascriptjavascript
const map = new Map();
map.set(NaN, "not a number");
 
console.log(map.get(NaN));             // "not a number"
console.log(map.get(Number("foo")));   // "not a number"

This identity-based comparison has a practical consequence: two different object literals with the same content are treated as different keys, because they are different references in memory:

javascriptjavascript
const map = new Map();
map.set({}, "first");
 
console.log(map.get({})); // undefined (different object reference)

Initializing a Map from an Array

You do not have to build a Map one set() call at a time. Pass an array of key-value pairs directly to the constructor, and it fills the Map in one step:

javascriptjavascript
const map = new Map([
  ["name", "Riley"],
  ["age", 30],
  ["active", true]
]);
 
console.log(map.get("name")); // "Riley"
console.log(map.size);        // 3

This pairs well with Object.entries() for converting plain objects to Maps. For more on that pattern, see the article on /javascript/javascript-object-keys-values-and-entries-guide.

Iterating Over a Map

Map is iterable. You can use for...of directly, which yields key-value pairs:

javascriptjavascript
const scores = new Map([
  ["math", 92],
  ["science", 87],
  ["english", 95]
]);
 
for (const [subject, score] of scores) {
  console.log(subject + ": " + score);
}

When you only need the keys or only the values, .keys() and .values() give you a focused iterator instead of the full pair:

javascriptjavascript
for (const subject of scores.keys()) {
  console.log(subject);
}
 
for (const score of scores.values()) {
  console.log(score);
}

.forEach() is another option, useful when you already have a callback-based iteration pattern elsewhere in the codebase and want the Map version to look the same:

javascriptjavascript
scores.forEach((score, subject) => {
  console.log(subject + " -> " + score);
});

Note the forEach callback order is (value, key). This matches array forEach, which calls back with (element, index) in that same value-first, key-second order, so the two methods feel consistent even though a Map's keys are not always numeric.

Cloning and Merging Maps

Clone a Map by passing it to the constructor:

javascriptjavascript
const original = new Map([["x", 10], ["y", 20]]);
const clone = new Map(original);
 
clone.set("x", 99);
console.log(original.get("x")); // 10 (independent)

Merge two Maps with the spread operator, the same way you would merge two plain objects. When both maps share a key, the later one wins:

javascriptjavascript
const first = new Map([["a", 1], ["b", 2]]);
const second = new Map([["b", 99], ["c", 3]]);
 
const merged = new Map([...first, ...second]);
 
console.log(merged.get("b")); // 99 (later value wins)

Spreading a Map produces an array of key-value pairs, which the constructor accepts.

Map vs Object: When to Use Each

Choosing between Map and Object

The decision comes down to key types, performance needs, and safety. If any of these apply, choose Map:

ScenarioWhy Map
Keys are not stringsMap accepts objects, functions, numbers as keys
Frequent additions and removalsMap is optimized for dynamic data
Keys come from user inputNo risk of prototype pollution
Need reliable insertion orderMap guarantees iteration order
Need the count quicklymap.size is O(1), Object.keys(obj).length is O(n)

Plain objects are the right choice when you have a fixed set of string keys, need JSON serialization, or are working with APIs that expect objects.

The Most Common Map Mistake

Setting a property on a Map with bracket or dot notation does not use the Map's data structure. It sets a regular object property that is invisible to Map methods:

javascriptjavascript
const map = new Map();
 
// Wrong: this sets a regular object property, not a Map entry
map["name"] = "Alex";
 
console.log(map.get("name")); // undefined
console.log(map.has("name")); // false
console.log(map.name);        // "Alex" (plain property, not Map data)

Always use map.set(key, value) and map.get(key). Never use bracket notation or dot notation to store data in a Map.

Converting Between Map and Object

Some APIs and JSON payloads expect a plain object, so you will occasionally need to convert in either direction. Going from Map to Object uses Object.fromEntries(), since a Map is already iterable as key-value pairs:

javascriptjavascript
const map = new Map([["theme", "dark"], ["fontSize", 16]]);
const obj = Object.fromEntries(map);
 
console.log(obj); // { theme: "dark", fontSize: 16 }

Going the other way, from Object to Map, uses Object.entries() to produce the key-value pairs that the Map constructor already knows how to accept:

javascriptjavascript
const obj = { theme: "dark", fontSize: 16 };
const map = new Map(Object.entries(obj));
 
console.log(map.get("theme")); // "dark"

For the companion collection type that stores unique values without keys, see the article on /javascript/javascript-set-object-complete-guide.

Rune AI

Rune AI

Key Insights

  • A Map holds key-value pairs where keys can be any type, including objects and functions.
  • Use set(key, value) and get(key) to add and retrieve entries.
  • Map preserves insertion order and has a convenient size property.
  • Iterate with for...of, forEach(), keys(), values(), or entries().
  • Never set properties on a Map with bracket notation -- use set() instead.
RunePowered by Rune AI

Frequently Asked Questions

When should I use a Map instead of an Object?

Use a Map when keys are not strings (objects, functions, numbers as keys), when insertion order matters, when you need to frequently add and remove entries, or when you want to avoid prototype pollution from user-provided keys.

Can I use objects as keys in a Map?

Yes. This is one of Map's superpowers. You can use objects, functions, arrays, and any primitive as keys. Object identity is used for comparison, not property values.

Does Map preserve insertion order?

Yes. Map iterates entries, keys, and values in the order they were first inserted. This is guaranteed by the specification, unlike plain objects where order is more complex.

Conclusion

Map is the right key-value collection when you need non-string keys, guaranteed insertion order, frequent additions and removals, or protection from inherited property collisions. For simple static data with string keys, a plain object is fine. But when performance, key flexibility, or safety matter, reach for Map.