Map & Set

Reviewed & published by Brayan K

Objects and arrays cover a lot of ground, but JavaScript has two purpose-built collections that do specific jobs better: Map for key/value pairs with any key type, and Set for collections of unique values.

Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Knowing when to reach for them — deduplicating a list, counting occurrences, caching by object key — is a hallmark of fluent, professional code.

What You'll Learn in This Lesson

📚 Prerequisites: Be comfortable with objects, arrays, and spread syntax — we use [...set] to convert collections back to arrays.

💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:

🗄️ Real-World Analogy: Think of two kinds of storage:

1️⃣ Map — Key/Value, the Right Way

A Map stores key/value pairs. You add with set(key, value), read with get(key), check with has(key), remove with delete(key), and count with the size property. Crucially, it remembers insertion order.

const scores = new Map();

scores.set("Ada", 95);
scores.set("Bo", 88);
scores.set("Cy", 73);

console.log(scores.get("Bo"));   // ✅ Expected output: 88
console.log(scores.has("Cy"));   // ✅ Expected output: true
console.log(scores.size);        // ✅ Expected output: 3  (a property, not a method)

scores.delete("Cy");
console.log(scores.size);        // ✅ Expected output: 2

2️⃣ Map Keys Can Be Anything

This is a Map's superpower over a plain object. Object keys are always coerced to strings, but a Map can use objects, functions, numbers, even booleans as keys. That makes it perfect for attaching data to specific object instances — a lightweight cache, for example.

const meta = new Map();

const user = { id: 1 };
const post = { id: 99 };

// Use the OBJECTS themselves as keys
meta.set(user, "is online");
meta.set(post, "is draft");

console.log(meta.get(user)); // ✅ Expected output: is online
console.log(meta.get(post)); // ✅ Expected output: is draft

// Number and boolean keys stay distinct (a plain object would stringify them)
const m = new Map();
m.set(1, "number one");
m.set("1", "string one");
console.log(m.size); // ✅ Expected output: 2

3️⃣ Iterating a Map

Maps are directly iterable in insertion order. Loop pairs with for...of (destructuring each [key, value]), or use map.keys(), map.values(), and map.entries(). Convert to an array with the spread operator when you need array methods.

const stock = new Map([
  ["apples", 12],
  ["pears", 5],
  ["plums", 8],
]);

// Loop key/value pairs in insertion order
for (const [fruit, qty] of stock) {
  console.log(fruit + ": " + qty);
}
// ✅ Expected output:
// apples: 12
// pears: 5
// plums: 8

// Total all quantities using values()
const total = [...stock.values()].reduce((a, n) => a + n, 0);
console.log(total); // ✅ Expected output: 25

🎯 Your Turn #1 — Build a Phone Book

Add a contact, then read it back.

const phonebook = new Map();

// 👉 add "Sam" -> "555-0101" using the right method
phonebook.___("Sam", "555-0101");

// 👉 read Sam's number back
console.log(phonebook.___("Sam")); // ✅ Expected output: 555-0101
console.log(phonebook.size);        // ✅ Expected output: 1

4️⃣ Set — A Collection of Unique Values

A Set holds unique values — add a duplicate and it's silently ignored. You add with add(value), test with has(value), remove with delete(value), and count with size. Membership checks are fast and read beautifully.

const visited = new Set();

visited.add("home");
visited.add("about");
visited.add("home"); // duplicate — ignored

console.log(visited.size);        // ✅ Expected output: 2
console.log(visited.has("about")); // ✅ Expected output: true
console.log(visited.has("shop"));  // ✅ Expected output: false

5️⃣ The Killer One-Liner: Deduplicate an Array

The most common reason to reach for a Set: removing duplicates from an array. Wrap the array in a Set to drop repeats, then spread it back into an array. One line, no nested loops.

const tags = ["js", "css", "js", "html", "css", "js"];

// Drop duplicates, back to an array
const unique = [...new Set(tags)];
console.log(unique); // ✅ Expected output: [ 'js', 'css', 'html' ]

// Count distinct values
console.log(new Set(tags).size); // ✅ Expected output: 3

// Works for numbers too
console.log([...new Set([1, 1, 2, 3, 3, 3])]); // ✅ Expected output: [ 1, 2, 3 ]

6️⃣ Set Math: Union, Intersection & Difference

Sets make classic "which items are in both lists / only this list" questions easy. Combine with spread for a union, and filter + has for intersection and difference.

const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);

// Union: everything from both
const union = [...new Set([...a, ...b])];
console.log(union); // ✅ Expected output: [ 1, 2, 3, 4, 5, 6 ]

// Intersection: in BOTH
const intersection = [...a].filter(x => b.has(x));
console.log(intersection); // ✅ Expected output: [ 3, 4 ]

// Difference: in a but NOT b
const difference = [...a].filter(x => !b.has(x));
console.log(difference); // ✅ Expected output: [ 1, 2 ]

🎯 Your Turn #2 — Remove Duplicates

Use a Set to produce a duplicate-free array.

const guests = ["Amy", "Bo", "Amy", "Cy", "Bo"];

// 👉 wrap in a Set to drop duplicates, then spread back into an array
const uniqueGuests = [...new ___(guests)];

console.log(uniqueGuests);        // ✅ Expected output: [ 'Amy', 'Bo', 'Cy' ]
console.log(uniqueGuests.length); // ✅ Expected output: 3

🧩 Reorder Challenge

These lines are scrambled. Reorder them so it logs the unique count 3.

Why: the Set must exist before you add to it, and the duplicate "red" is ignored — so the final size is 3.

🧠 Quick Recall

Predict the output before revealing the answer.

3 — a Set keeps only unique values: 1, 2, and 3.

9 — setting an existing key overwrites its value; set returns the Map so you can chain.

2 — objects are compared by reference, so two different {} objects are distinct values.

Common Errors & Fixes

Quick Reference — Map & Set

TaskMapSet
Createnew Map()new Set()
Addmap.set(k, v)set.add(v)
Readmap.get(k)set.has(v)
Checkmap.has(k)set.has(v)
Removemap.delete(k)set.delete(v)
Countmap.sizeset.size

Lesson Complete — Map & Set!

Practice quiz

How do you count the items in a Map or Set?

  • The .length property
  • The .size property
  • The .count() method
  • The .size() method

Answer: The .size property. Maps and Sets expose .size as a property (no parentheses); .length is for arrays.

What is logged? const m = new Map(); m.set(1, 'a'); m.set('1', 'b'); console.log(m.size);

  • 1
  • 2
  • undefined
  • It throws

Answer: 2. A Map keeps the number 1 and the string '1' as distinct keys, so the size is 2.

What is the idiomatic one-liner to remove duplicates from an array named tags?

  • tags.unique()
  • [...new Set(tags)]
  • new Set(tags).toArray()
  • Array.dedupe(tags)

Answer: [...new Set(tags)]. Wrapping an array in a Set drops duplicates; spreading it back gives a deduplicated array.

How does a Set decide whether two values are duplicates?

  • By deep content comparison
  • Using SameValueZero (=== with NaN equal to NaN)
  • By converting both to strings
  • By their .toString() output

Answer: Using SameValueZero (=== with NaN equal to NaN). Sets use SameValueZero: essentially === except NaN equals NaN. Objects compare by reference.

What is logged? const s = new Set(); s.add({}); s.add({}); console.log(s.size);

  • 0
  • 1
  • 2
  • It throws

Answer: 2. Objects are compared by reference, so two different {} objects are two distinct values.

Which method reads a value from a Map by its key?

  • map.read(key)
  • map[key]
  • map.get(key)
  • map.value(key)

Answer: map.get(key). Use map.get(key). Bracket notation sets a plain property instead of a Map entry.

What advantage does a Map have over a plain object for keys?

  • Keys can be any type, including objects
  • Keys are always sorted alphabetically
  • Keys must be strings
  • Keys cannot be deleted

Answer: Keys can be any type, including objects. Object keys are coerced to strings, but a Map can use objects, functions, numbers, and booleans as keys.

What is logged? m.set('a', 1).set('a', 9); console.log(m.get('a'));

  • 1
  • 9
  • [1, 9]
  • undefined

Answer: 9. Setting an existing key overwrites its value, and set returns the Map so calls can be chained.

Given a = new Set([1,2,3,4]) and b = new Set([3,4,5,6]), what is the intersection [...a].filter(x => b.has(x))?

  • [1, 2]
  • [3, 4]
  • [5, 6]
  • [1, 2, 3, 4, 5, 6]

Answer: [3, 4]. Intersection keeps values present in both sets: 3 and 4.

How do you loop over a Map's key/value pairs in insertion order?

  • for (const [k, v] of map)
  • for (const k in map)
  • map.forEachPair()
  • for (const v of map.keys())

Answer: for (const [k, v] of map). Maps are iterable in insertion order; for...of with [key, value] destructuring reads each pair.

Continue this course

Frequently asked questions

When should I use a Map instead of a plain object?

Reach for a Map when keys aren't simple strings — Maps allow any key type, including objects and functions. Maps also remember insertion order, give you a reliable .size, and are easy to iterate. If your data is just string keys describing a record, a plain object is fine; for a true key/value collection that you add to and read from dynamically, a Map is cleaner.

What does a Set do that an array can't?

A Set automatically rejects duplicates — every value is unique. Checking membership with set.has(x) is also fast and reads clearly, whereas arr.includes(x) scans the array. The classic one-liner [...new Set(arr)] deduplicates an array in a single step.

How do I get the number of items in a Map or Set?

Use the .size property — note it's a property, not a method, so no parentheses: map.size, set.size. This is unlike arrays, which use .length, and unlike plain objects, which have no built-in count at all (you'd write Object.keys(obj).length).

How does a Set decide two values are equal?

It uses SameValueZero, which is essentially === with one tweak: NaN is considered equal to NaN. Crucially, objects are compared by reference, so two different objects with identical contents count as two distinct values. Only the exact same object reference is treated as a duplicate.

Can I convert between Maps, Sets, arrays, and objects?

Yes, freely. Spread or Array.from turns a Set into an array ([...set]) and a Map into an array of [key, value] pairs. new Map(Object.entries(obj)) builds a Map from an object, and Object.fromEntries(map) goes back. These conversions make it easy to use the right structure for each step.

Related lessons