JavaScriptIntermediate

JavaScript Map and Set: Keys, Values and Iteration Explained

Learn JavaScript Map and Set: create them, add and read items, loop over them, remove duplicates, and know when to use them instead of objects and arrays.

All JavaScript lessons

What you will learn

So far you have stored data in arrays (ordered lists) and objects (named properties). JavaScript also has two special collections made for specific jobs: Map, which stores key-value pairs where the key can be any type, and Set, which stores unique values only. In this lesson you will learn how to create them, add, read and remove items, loop over them, and when they are a better choice than plain objects and arrays.

Map: key-value pairs

A Map is like an object, but with more power. You store a value under a key, and later you get the value back using the same key.

Creating a Map

// An empty Map
const scores = new Map();

// A Map with starting data (an array of [key, value] pairs)
const ages = new Map([
  ["Riya", 22],
  ["Karan", 25],
  ["Neha", 21]
]);

console.log(ages);   // Map(3) { "Riya" => 22, "Karan" => 25, "Neha" => 21 }

The main methods

Method / property What it does
map.set(key, value) Adds or updates an entry (returns the map, so you can chain)
map.get(key) Returns the value, or undefined if the key is missing
map.has(key) Returns true or false
map.delete(key) Removes an entry (returns true if it existed)
map.clear() Removes everything
map.size The number of entries (a property, not a method)
const scores = new Map();

scores.set("Riya", 90);
scores.set("Karan", 75);
scores.set("Riya", 95);   // same key: the value is updated

console.log(scores.get("Riya"));     // 95
console.log(scores.get("Neha"));     // undefined
console.log(scores.has("Karan"));    // true
console.log(scores.size);            // 2

scores.delete("Karan");
console.log(scores.size);            // 1

scores.clear();
console.log(scores.size);            // 0

Because set returns the map, you can chain:

const colors = new Map()
  .set("red", "#ff0000")
  .set("green", "#00ff00")
  .set("blue", "#0000ff");

console.log(colors.size);   // 3

Keys can be anything

This is the biggest difference from objects. An object turns every key into text (or a symbol). A Map keeps the key as it is: numbers, booleans, objects, functions, anything.

const map = new Map();

map.set(1, "number one");
map.set("1", "text one");
map.set(true, "boolean true");

console.log(map.get(1));      // "number one"
console.log(map.get("1"));    // "text one" (a different key)
console.log(map.get(true));   // "boolean true"

Using an object as a key:

const riya = { name: "Riya" };
const karan = { name: "Karan" };

const visits = new Map();
visits.set(riya, 3);
visits.set(karan, 7);

console.log(visits.get(riya));    // 3
console.log(visits.get({ name: "Riya" }));   // undefined (a different object!)

Objects are compared by reference, so you must use the same object to get the value back.

Good to know: NaN can be used as a key, and map.get(NaN) works. A Map treats NaN as equal to NaN, and 0 as equal to -0.

Order is kept

A Map remembers the order in which entries were added, and loops follow that order.

Looping over a Map

const prices = new Map([
  ["pen", 10],
  ["book", 120],
  ["bag", 800]
]);

// 1. for...of gives [key, value] pairs (use destructuring)
for (const [item, price] of prices) {
  console.log(item, price);
}

// 2. Only keys
for (const key of prices.keys()) {
  console.log(key);   // "pen", "book", "bag"
}

// 3. Only values
for (const value of prices.values()) {
  console.log(value);   // 10, 120, 800
}

// 4. forEach (note the order: value first, then key)
prices.forEach((value, key) => {
  console.log(key, value);
});

Converting between Map, arrays and objects

const prices = new Map([
  ["pen", 10],
  ["book", 120]
]);

// Map to array
console.log([...prices]);          // [["pen", 10], ["book", 120]]
console.log([...prices.keys()]);   // ["pen", "book"]
console.log(Array.from(prices.values()));   // [10, 120]

// Map to object
console.log(Object.fromEntries(prices));    // { pen: 10, book: 120 }

// Object to Map
const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));
console.log(map);   // Map(2) { "a" => 1, "b" => 2 }

Since a Map is iterable, array tools work after you convert it:

const prices = new Map([["pen", 10], ["book", 120], ["bag", 800]]);

const expensive = [...prices].filter(([item, price]) => price > 100);
console.log(expensive);   // [["book", 120], ["bag", 800]]

const total = [...prices.values()].reduce((sum, p) => sum + p, 0);
console.log(total);   // 930

Map vs plain object

Map Object
Key types Any type Text and symbols only
Order Insertion order, guaranteed Mostly insertion order, but numeric-like keys are sorted first
Size map.size Object.keys(obj).length
Iteration Directly iterable Needs Object.keys, values, entries
Extra keys None (clean) Inherited keys like toString exist
Best for Many additions and removals, unknown keys, non-text keys Fixed structure, records like { name, age }, JSON

Rule of thumb: use an object for a fixed record (like a user with name and age). Use a Map for a dynamic dictionary where keys come from data and change often.

One more detail: a Map does not convert to JSON directly.

const map = new Map([["a", 1]]);

console.log(JSON.stringify(map));                      // "{}" (data is lost!)
console.log(JSON.stringify(Object.fromEntries(map)));  // '{"a":1}'

Set: unique values

A Set is a collection of unique values. If you add the same value twice, it is stored only once.

Creating a Set

const tags = new Set();

const numbers = new Set([1, 2, 2, 3, 3, 3]);

console.log(numbers);        // Set(3) { 1, 2, 3 }
console.log(numbers.size);   // 3

The main methods

Method / property What it does
set.add(value) Adds a value (ignored if already present; returns the set)
set.has(value) Returns true or false
set.delete(value) Removes a value (returns true if it existed)
set.clear() Removes everything
set.size The number of values
const skills = new Set();

skills.add("HTML");
skills.add("CSS");
skills.add("HTML");   // ignored, already there

console.log(skills.size);          // 2
console.log(skills.has("CSS"));    // true
console.log(skills.has("React"));  // false

skills.delete("CSS");
console.log(skills);               // Set(1) { "HTML" }

Like Map, a Set keeps insertion order, and it treats NaN as equal to NaN.

Objects in a Set

Primitives are compared by value, but objects by reference:

const set = new Set();

set.add({ id: 1 });
set.add({ id: 1 });   // a different object, so it is added again

console.log(set.size);   // 2

Looping over a Set

const colors = new Set(["red", "green", "blue"]);

for (const color of colors) {
  console.log(color);
}

colors.forEach((color) => console.log(color));

console.log([...colors]);   // ["red", "green", "blue"]

A Set has keys(), values() and entries() too, but they exist only to match Map. For a Set, values() and keys() are the same thing.

Set vs array

Set Array
Duplicates Not allowed Allowed
Access by index No (set[0] does not work) Yes
Check if a value exists set.has(x) (fast) array.includes(x) (slower on big lists)
Array methods (map, filter) Not available (convert first) Available
Best for Unique values, fast lookups Ordered lists, positions

Set operations

Sets are perfect for “union”, “intersection” and “difference”. You can write them with spread and filter:

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]);   // [1, 2, 3, 4, 5, 6]

// Intersection: only in both
const intersection = new Set([...a].filter((x) => b.has(x)));
console.log([...intersection]);   // [3, 4]

// Difference: in a but not in b
const difference = new Set([...a].filter((x) => !b.has(x)));
console.log([...difference]);   // [1, 2]

Newer JavaScript engines also have built-in methods like a.union(b), a.intersection(b) and a.difference(b). They are not available in older browsers, so check support before you use them. The spread version above works everywhere.

Real-life use cases

1. Remove duplicates from an array

const emails = ["a@x.com", "b@x.com", "a@x.com", "c@x.com", "b@x.com"];

const unique = [...new Set(emails)];

console.log(unique);   // ["a@x.com", "b@x.com", "c@x.com"]

This is the most common use of Set.

2. Count how often something appears (Map)

const votes = ["red", "blue", "red", "green", "red", "blue"];

const counts = new Map();

for (const vote of votes) {
  counts.set(vote, (counts.get(vote) ?? 0) + 1);
}

console.log(counts);   // Map(3) { "red" => 3, "blue" => 2, "green" => 1 }

// Find the winner
const winner = [...counts].sort((a, b) => b[1] - a[1])[0];
console.log(winner);   // ["red", 3]

3. Group items by a property (Map)

const students = [
  { name: "Riya", grade: "A" },
  { name: "Karan", grade: "B" },
  { name: "Neha", grade: "A" }
];

const byGrade = new Map();

for (const student of students) {
  if (!byGrade.has(student.grade)) {
    byGrade.set(student.grade, []);
  }
  byGrade.get(student.grade).push(student.name);
}

console.log(byGrade);   // Map(2) { "A" => ["Riya", "Neha"], "B" => ["Karan"] }

4. Cache (memoization)

const cache = new Map();

function square(n) {
  if (cache.has(n)) {
    console.log("from cache");
    return cache.get(n);
  }

  const result = n * n;
  cache.set(n, result);
  return result;
}

console.log(square(5));   // 25
console.log(square(5));   // "from cache", then 25

5. Store extra data about objects (objects as keys)

const button1 = { id: "save" };
const button2 = { id: "cancel" };

const clickCounts = new Map();
clickCounts.set(button1, 0);
clickCounts.set(button2, 0);

clickCounts.set(button1, clickCounts.get(button1) + 1);

console.log(clickCounts.get(button1));   // 1

6. Track visited items and avoid repeats (Set)

const seen = new Set();
const ids = [1, 2, 3, 2, 1, 4];

for (const id of ids) {
  if (seen.has(id)) {
    console.log("duplicate:", id);
    continue;
  }
  seen.add(id);
}

console.log([...seen]);   // [1, 2, 3, 4]

7. Find the common tags of two posts (Set)

const postA = new Set(["js", "arrays", "tips"]);
const postB = new Set(["js", "objects", "tips"]);

const common = [...postA].filter((tag) => postB.has(tag));
console.log(common);   // ["js", "tips"]

8. Check if all items are unique

function allUnique(list) {
  return new Set(list).size === list.length;
}

console.log(allUnique([1, 2, 3]));      // true
console.log(allUnique([1, 2, 2, 3]));   // false

9. A lookup table for fast checks

const blockedWords = new Set(["spam", "scam", "fake"]);

function isBlocked(word) {
  return blockedWords.has(word.toLowerCase());
}

console.log(isBlocked("SPAM"));   // true
console.log(isBlocked("hello"));  // false

10. Unique characters in a word

const word = "mississippi";

console.log([...new Set(word)].join(""));   // "misp"
console.log(new Set(word).size);            // 4

Common mistakes

  • Using map.length or set.length. The correct property is size.
  • Using map["key"] = value. That sets an ordinary property on the Map object, not an entry. Use map.set("key", value).
  • Using set[0]. Sets have no index. Convert with [...set][0] if you need it.
  • Trying to get an object key with a new but equal object. Keep a reference to the original object.
  • Expecting a Set to remove duplicate objects like { id: 1 } and { id: 1 }. They are different objects. Use the id values in a Set instead.
  • Expecting JSON.stringify(map) to work. Convert to an object or array first.
  • Using map.forEach((key, value) => ...). The order is (value, key).
  • Calling array methods directly on a Map or Set. map.map(...) does not exist. Use [...map].map(...).
  • Using a Map when a plain object is enough. For a small, fixed record like a user, an object is simpler and works with JSON.

Practice

  1. Create a Map of 3 countries and their capitals. Print the capital of one country, check a missing country with has, and print the size.
  2. Loop over your Map with for...of and print "<country> -> <capital>".
  3. Update one value and delete one entry. Print the Map again.
  4. Convert your Map to an object with Object.fromEntries, and then back to a Map.
  5. Use a Set to remove the duplicates from [5, 1, 5, 2, 1, 3].
  6. Write a function that counts how many unique letters are in a word.
  7. Count the words in "to be or not to be" using a Map, and print the result.
  8. Given two Sets of numbers, print their union, intersection and difference.
  9. Use a Map to store how many times each of two button objects was clicked.
  10. Challenge: write groupBy(list, key) that returns a Map where each key is the value of that property and each value is an array of matching items.

Recap

  • Map stores key-value pairs. Keys can be any type, and the order of insertion is kept.
  • Map methods: set, get, has, delete, clear, and the property size. Loop with for (const [key, value] of map), keys(), values() or forEach.
  • Use Object.fromEntries(map) and new Map(Object.entries(obj)) to convert between objects and Maps. A Map does not work directly with JSON.stringify.
  • Set stores unique values. Methods: add, has, delete, clear, and size. It has no index access.
  • [...new Set(array)] removes duplicates. Sets also make union, intersection and difference easy.
  • Objects are compared by reference in both Maps and Sets.
  • Use a Map for dynamic dictionaries, counting, grouping and caching. Use a Set for unique values and fast has checks. Use plain objects and arrays for simple records and ordered lists.
  • Next you will learn WeakMap and WeakSet, special versions that let JavaScript clean up memory automatically.