In short
JavaScript Map, Set, WeakMap and WeakSet are special collections. Learn when a Map beats a plain object, how a Set removes duplicates, and what weak collections are for. What is a Map in JavaScript? A Map is a collection of key–value pairs, like an object.
JavaScript Map, Set, WeakMap and WeakSet are special collections. Learn when a Map beats a plain object, how a Set removes duplicates, and what weak collections are for.
What is a Map in JavaScript?
A Map is a collection of key–value pairs, like an object. Think of it as a row of labelled boxes: you put a value in a box and stick a label (the key) on it.
The big difference is that a Map key can be any value: a string, a number, an object, even a DOM element. In a plain object, keys are always turned into strings.
const prices = new Map();
prices.set('apple', 0.5); // add a key and a value
prices.set('banana', 0.25);
prices.set('cherry', 3);
console.log(prices.get('apple')); // Output: 0.5
console.log(prices.has('banana')); // Output: true
console.log(prices.size); // Output: 3
prices.delete('cherry'); // remove one entry
for (const [fruit, price] of prices) {
console.log(`${fruit} costs $${price}`);
}
// Output:
// apple costs $0.5
// banana costs $0.25
set() adds or updates an entry, get() reads it, has() checks if a key exists, and size tells you how many entries there are. A Map also remembers the order you added things, so the for...of loop gives you entries in that order.
Map vs object: which one should you use?
Both store key–value pairs, so how do you choose? Here is a simple guide.
| Question | Plain object | Map |
|---|---|---|
| What can a key be? | Strings (and symbols) | Any value |
| How do I count entries? | Object.keys(obj).length | map.size |
| Can I loop it directly? | No, use Object.entries() | Yes, with for...of |
| Good for JSON? | Yes, works with JSON.stringify | No, convert it first |
| Best use | Fixed "shape" data like a user profile | Lookups that grow and shrink a lot |
Use an object for a record with known fields, like { name, email, age }. Use a Map when you add and remove many keys while the program runs, or when your keys are not strings.
// Count how many times each word appears
const text = 'the cat and the dog and the bird';
const counts = new Map();
for (const word of text.split(' ')) {
counts.set(word, (counts.get(word) ?? 0) + 1);
}
console.log(counts.get('the')); // Output: 3
console.log([...counts]);
// Output: [["the",3],["cat",1],["and",2],["dog",1],["bird",1]]
For each word, we read the current count (or 0 if the word is new) and add one. The spread [...counts] turns the Map into an array of pairs so you can see it all.
Using a Set for unique values
A Set is a collection where every value appears only once. It is like a guest list: if you write the same name twice, the person still gets one seat.
const tags = new Set();
tags.add('javascript');
tags.add('css');
tags.add('javascript'); // ignored, it is already there
console.log(tags.size); // Output: 2
console.log(tags.has('css')); // Output: true
tags.delete('css');
console.log([...tags]); // Output: ["javascript"]
How to remove duplicates from an array
The most popular trick with a Set is removing duplicates from an array in one line.
const emails = ['ana@mail.com', 'ben@mail.com', 'ana@mail.com', 'cara@mail.com'];
const uniqueEmails = [...new Set(emails)];
console.log(uniqueEmails);
// Output: ["ana@mail.com", "ben@mail.com", "cara@mail.com"]
new Set(emails) keeps only the first copy of each value. The spread [...] turns the Set back into a normal array.
Common mistake: A Set compares objects by reference, not by content.
new Set([{ id: 1 }, { id: 1 }])has a size of 2, because they are two different objects that only look the same.
Set methods: union, intersection and difference
Modern browsers have built-in methods to combine Sets. Imagine two clubs and you want to compare their members.
const chessClub = new Set(['Ana', 'Ben', 'Cara']);
const musicClub = new Set(['Ben', 'Dan', 'Cara']);
console.log([...chessClub.union(musicClub)]);
// Output: ["Ana", "Ben", "Cara", "Dan"] (in either club)
console.log([...chessClub.intersection(musicClub)]);
// Output: ["Ben", "Cara"] (in both clubs)
console.log([...chessClub.difference(musicClub)]);
// Output: ["Ana"] (only in the chess club)
console.log(new Set(['Ben']).isSubsetOf(chessClub));
// Output: true
There is also symmetricDifference() (in one club but not both), isSupersetOf() and isDisjointFrom().
Note: These Set methods arrived in all major browsers in 2024 (Chrome 122, Firefox 127, Safari 17). If you must support older browsers, use the array way instead, for example
[...a].filter(x => b.has(x))for an intersection.
What are WeakMap and WeakSet for?
A WeakMap is a Map where the keys must be objects, and it holds them "weakly". That means: if nothing else in your program uses that object any more, JavaScript can throw it away (this cleanup is called garbage collection), and the WeakMap entry disappears too.
A real-life comparison: a coat check that automatically throws away the ticket when the coat's owner leaves the building forever. You never have to clean up by hand.
A common use is storing extra private data about DOM elements without changing the elements themselves.
const clickCounts = new WeakMap();
document.querySelectorAll('button').forEach((button) => {
clickCounts.set(button, 0);
button.addEventListener('click', () => {
clickCounts.set(button, clickCounts.get(button) + 1);
console.log(`Clicked ${clickCounts.get(button)} times`);
});
});
// Output after clicking a button twice: Clicked 1 times, Clicked 2 times
If a button is removed from the page and no other code points to it, its entry in clickCounts can be cleaned up automatically. That avoids memory leaks (memory that is never freed).
A WeakSet is the same idea for a Set: it holds objects only, for example to remember "which elements did I already set up?". Weak collections cannot be looped over and have no size, because their contents can vanish at any moment.
Practice exercise
You have an array of product categories from a shop: ['shoes', 'hats', 'shoes', 'bags', 'hats', 'socks']. First, make an array with no duplicates. Then use a Map to count how many times each category appears, and log the result as shoes: 2 and so on.
Hint: use [...new Set(array)] for the first part, and map.get(key) ?? 0 for the counting part.
Key takeaways
- A Map stores key–value pairs where keys can be any value, keeps insertion order, and has a handy
size. - Use plain objects for fixed records and JSON; use a Map for frequently changing lookups.
- A Set stores unique values, and
[...new Set(array)]removes duplicates. - Newer Set methods like
union()andintersection()work in all modern browsers since 2024. - WeakMap and WeakSet hold objects weakly, so data about removed objects is cleaned up automatically.