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.
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:
NaNcan be used as a key, andmap.get(NaN)works. AMaptreatsNaNas equal toNaN, and0as 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.lengthorset.length. The correct property issize. - Using
map["key"] = value. That sets an ordinary property on the Map object, not an entry. Usemap.set("key", value). - Using
set[0]. Sets have no index. Convert with[...set][0]if you need it. - Trying to
getan 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 theidvalues 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
- Create a Map of 3 countries and their capitals. Print the capital of one country, check a missing country with
has, and print thesize. - Loop over your Map with
for...ofand print"<country> -> <capital>". - Update one value and delete one entry. Print the Map again.
- Convert your Map to an object with
Object.fromEntries, and then back to a Map. - Use a
Setto remove the duplicates from[5, 1, 5, 2, 1, 3]. - Write a function that counts how many unique letters are in a word.
- Count the words in
"to be or not to be"using a Map, and print the result. - Given two Sets of numbers, print their union, intersection and difference.
- Use a Map to store how many times each of two button objects was clicked.
- 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
Mapstores key-value pairs. Keys can be any type, and the order of insertion is kept.- Map methods:
set,get,has,delete,clear, and the propertysize. Loop withfor (const [key, value] of map),keys(),values()orforEach. - Use
Object.fromEntries(map)andnew Map(Object.entries(obj))to convert between objects and Maps. A Map does not work directly withJSON.stringify. Setstores unique values. Methods:add,has,delete,clear, andsize. 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
haschecks. Use plain objects and arrays for simple records and ordered lists. - Next you will learn
WeakMapandWeakSet, special versions that let JavaScript clean up memory automatically.