1. Introduction
Before ES6, developers used plain objects as key-value stores and arrays with manual duplicate-checking as sets. ES6 introduced two purpose-built collection types: Map, a true key-value store where keys can be of any type, and Set, a collection that stores only unique values. Both maintain insertion order and provide a cleaner, more predictable API than repurposing objects and arrays.
Cricket analogy: Like retiring the old habit of using a generic ledger and manually checking for duplicate player names on a roster, in favor of a purpose-built squad registry (Map) keyed by any identifier and a duplicate-free playing XI list (Set) that maintains selection order automatically.
2. Syntax
// Map
const map = new Map();
map.set('name', 'Ada');
map.set(1, 'one');
map.get('name'); // 'Ada'
map.has(1); // true
map.delete(1);
map.size; // 1
// Set
const set = new Set([1, 2, 2, 3]);
set.add(4);
set.has(2); // true
set.delete(1);
set.size; // 3
// Iterating
for (const [key, value] of map) { /* ... */ }
for (const value of set) { /* ... */ }3. Explanation
A Map associates keys with values just like an object, but with important upgrades: any value — an object, a function, NaN, even another Map — can be used as a key, not just strings and symbols. Map also preserves the exact insertion order of its entries when you iterate over it, and it exposes a .size property directly, whereas checking an object's number of keys requires Object.keys(obj).length.
Cricket analogy: Like a coach's tactical notebook where you can key notes not just by player name but by an entire lineup object or even another notebook, and it instantly tells you the note count via .size without counting entries by hand, unlike a plain roster sheet.
A Set stores a collection of values with no duplicates. When you add a value that already exists, it is silently ignored. Equality for Set (and for Map keys) is based on the SameValueZero algorithm, which behaves like strict equality (===) except that it treats NaN as equal to itself (so a Set can only ever contain one NaN).
Cricket analogy: Like a 'players who've scored a century this series' list that silently ignores adding the same player twice, and treats a rain-out edge case as consistently equal to itself, unlike stricter comparisons elsewhere.
Gotcha — plain objects vs Map: object keys are always coerced to strings (or symbols), so obj[1] and obj['1'] refer to the same property, and you cannot use an object as a key without it collapsing to '[object Object]'. Map keeps keys exactly as given: const k1 = {}; const k2 = {}; map.set(k1, 'a').set(k2, 'b'); creates two distinct entries because k1 and k2 are different object references.
Gotcha — Set equality with SameValueZero: new Set([NaN, NaN]).size is 1 (NaN is treated as equal to itself in a Set, unlike NaN === NaN which is false), but new Set([{}, {}]).size is 2, because two distinct object literals are never equal, even if their contents look the same.
4. Example
const inventory = new Map();
inventory.set('apples', 10);
inventory.set('bananas', 5);
inventory.set('apples', 12); // overwrites existing key
for (const [item, qty] of inventory) {
console.log(item, qty);
}
console.log('Map size:', inventory.size);
const tags = new Set(['js', 'web', 'js', 'frontend']);
tags.add('js');
console.log([...tags]);
console.log('Set size:', tags.size);5. Output
apples 12
bananas 5
Map size: 2
[ 'js', 'web', 'frontend' ]
Set size: 36. Key Takeaways
- Map is a key-value store where keys can be any type (objects, functions, primitives) unlike plain objects limited to strings/symbols.
- Map preserves insertion order when iterated and exposes .size directly.
- Set stores only unique values, silently ignoring duplicate .add() calls.
- Both Map and Set use SameValueZero equality, so NaN is treated as equal to itself, but two distinct objects are never equal.
- Both are iterable with for...of and can be spread into arrays with [...map] / [...set].
- Use Map over an object when keys are dynamic, non-string, or when insertion order and frequent size checks matter.
Practice what you learned
1. Why might you choose a Map over a plain object for a key-value store?
2. What is the size of `new Set([NaN, NaN, 1, 1])`?
3. What happens when you call set.add(value) with a value already in the Set?
4. How do you check the number of entries in a Map?
5. Given `const k1 = {}, k2 = {}; const m = new Map([[k1,'a'],[k2,'b']]);`, what is m.size?
Was this page helpful?
You May Also Like
Objects in JavaScript
Learn how to create, access, and modify JavaScript objects, and understand why objects behave as reference types.
Arrays in JavaScript
Understand how JavaScript arrays store ordered lists of values, how indexing and length work, and why `typeof` alone can't identify an array.
Common Array Methods in JavaScript
Explore the most-used array methods, split into mutating methods that change the original array and non-mutating methods that return a new array.
Iterators and Generators in JavaScript
The iterator protocol behind for...of, and how generator functions with function*/yield produce values lazily and can pause/resume execution.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics