By the end of this lesson, you will be able to create, read, update, and iterate over JavaScript Maps, and choose them over plain objects when keys must be arbitrary values or insertion order matters.
What it is
A Map is a built-in collection that stores key-value pairs. Unlike a plain object, a Map key can be any JavaScript value: a string, number, boolean, object, array, function, or null. Maps remember insertion order and expose a size property.
Think of a Map as a dictionary with typed keys. Each key is unique; setting the same key again replaces the old value. Related terms: entry, key, value, iteration, and SameValueZero, the comparison Maps use to decide whether two keys are the same.
Why it matters
- Use Maps when keys are not naturally strings, such as objects, arrays, or DOM nodes.
- Use Maps when you need reliable insertion order and a simple
sizeproperty. - Use Maps to avoid accidental prototype properties like
toStringorconstructor. - Use Maps for caches, counters, and lookup tables where entries are added and removed frequently.
Syntax or steps
Create a Map with new Map() or pass an iterable of pairs. Add or update entries with set(key, value). Read with get(key). Check existence with has(key). Remove with delete(key). Empty with clear().
const map = new Map();
map.set("name", "Ada");
map.set(42, "answer");
map.set([1, 2], "array key");
const value = map.get("name");
const exists = map.has(42);
map.delete("name");
Example
This example uses different key types, updates a value, and iterates over entries.
const user = { id: 7 };
const roles = new Map([
[user, "admin"],
["guest", "viewer"],
[42, "special number"]
]);
roles.set(user, "owner");
console.log(roles.get(user)); // "owner"
console.log(roles.has("guest")); // true
console.log(roles.size); // 3
for (const [key, value] of roles) {
console.log(key, value);
}
Part by part: new Map([[user, "admin"]]) initializes entries from an array of pairs. roles.set(user, "owner") replaces the value for the same object reference. roles.get(user) retrieves that value. The for...of loop destructures each entry into key and value.
Common mistakes
- Trying to access values with dot notation, such as
map.name. Usemap.get("name")instead. - Assuming two similar objects are the same key.
{ id: 1 }and{ id: 1 }are different references, so they create different entries. - Forgetting that Maps are not JSON serializable by default.
JSON.stringify(map)returns"{}"; convert entries to an array first. - Expecting
NaNto fail as a key. Maps use SameValueZero, soNaNcan be a key and0and-0are treated as the same key.
When to use it
Compare Maps with plain objects. Objects are best for fixed records with string keys and JSON compatibility. Maps are best for dynamic collections with arbitrary keys and guaranteed insertion order.
| Need | Use | Why |
|---|---|---|
| Keys are strings or symbols | Object | Simpler syntax and JSON-friendly. |
| Keys are objects, arrays, or mixed types | Map | Any value can be a key. |
| Need insertion order | Map | Iteration order is guaranteed. |
| Need frequent add/delete and size | Map | Built-in methods and size. |
Practice
Guided exercise: create a Map that stores three users by their object references, then log the size and one value.
const a = { name: "A" };
const b = { name: "B" };
const c = { name: "C" };
const users = new Map([
[a, "active"],
[b, "inactive"],
[c, "pending"]
]);
console.log(users.size);
console.log(users.get(b));
Expected output: 3 and inactive.
Challenge: write a function that counts how many times each word appears in an array, using a Map.
function countWords(words) {
const counts = new Map();
for (const word of words) {
counts.set(word, (counts.get(word) || 0) + 1);
}
return counts;
}
Quick check
Question: Why does map.set({ id: 1 }, "one") followed by map.get({ id: 1 }) return undefined?
Answer: Because each object literal creates a new reference. Map keys are compared by reference for objects, so the second object is not the same key as the first.
Summary
JavaScript Maps are ordered key-value collections that accept any value as a key. Use them when you need arbitrary keys, reliable iteration order, or a clean collection API. Choose plain objects when you need simple string-keyed records and JSON serialization.