Introduction
While objects and arrays handle most data storage needs, ES6 introduced Map and Set for specialized use cases. Maps allow any value as a key (not just strings), and Sets store only unique values. These data structures solve problems that are awkward with plain objects and arrays.
Key Concepts
Map: A collection of key-value pairs where keys can be any type (objects, functions, primitives).
Set: A collection of unique values—duplicates are automatically ignored.
WeakMap/WeakSet: Variants that hold weak references, allowing garbage collection.
Real World Context
Maps are perfect for caching (using objects as keys), counting occurrences, and storing metadata about DOM elements. Sets excel at deduplication, tracking unique visitors, and implementing tags or categories.
Deep Dive
Map Basics
javascriptconst map = new Map(); // Set and get map.set('name', 'Alice'); map.set(1, 'one'); // Number as key map.set({ id: 1 }, 'user'); // Object as key map.get('name'); // 'Alice' map.get(1); // 'one' // Size and existence map.size; // 3 map.has('name'); // true // Delete map.delete('name'); map.clear(); // Remove all
Map Iteration
javascriptconst map = new Map([ ['a', 1], ['b', 2], ['c', 3] ]); // Iterate entries for (const [key, value] of map) { console.log(key, value); } // Other iterators map.keys(); // Iterator of keys map.values(); // Iterator of values map.entries(); // Iterator of [key, value] // forEach map.forEach((value, key) => console.log(key, value));
Map vs Object
javascript// Objects convert keys to strings const obj = {}; obj[1] = 'one'; obj['1'] = 'string one'; console.log(obj); // { '1': 'string one' } - key collision! // Maps preserve key types const map = new Map(); map.set(1, 'number one'); map.set('1', 'string one'); map.get(1); // 'number one' map.get('1'); // 'string one' - no collision!
Set Basics
javascriptconst set = new Set([1, 2, 2, 3, 3, 3]); console.log(set.size); // 3 (duplicates removed) // Add and check set.add(4); set.has(2); // true // Delete set.delete(1); set.clear(); // Remove all // Convert to array const arr = [...set]; const arr2 = Array.from(set);
Set for Deduplication
javascriptconst numbers = [1, 2, 2, 3, 3, 3, 4]; const unique = [...new Set(numbers)]; // [1, 2, 3, 4] // Set operations const a = new Set([1, 2, 3]); const b = new Set([2, 3, 4]); // Union const union = new Set([...a, ...b]); // {1, 2, 3, 4} // Intersection const intersection = new Set([...a].filter(x => b.has(x))); // {2, 3} // Difference const difference = new Set([...a].filter(x => !b.has(x))); // {1}
WeakMap and WeakSet
javascript// Keys must be objects, and are weakly held const weakMap = new WeakMap(); let obj = { id: 1 }; weakMap.set(obj, 'metadata'); obj = null; // Now the entry can be garbage collected // Use case: storing private data for objects const privateData = new WeakMap(); class User { constructor(name) { privateData.set(this, { name }); } getName() { return privateData.get(this).name; } }
Set Methods (ES2025)
ES2025 brings native Set methods that eliminate the need for spread+filter workarounds:
javascriptconst a = new Set([1, 2, 3]); const b = new Set([2, 3, 4]); // Union — all elements from both sets a.union(b); // Set {1, 2, 3, 4} // Intersection — elements in both sets a.intersection(b); // Set {2, 3} // Difference — elements in a but not in b a.difference(b); // Set {1} // Symmetric difference — elements in either but not both a.symmetricDifference(b); // Set {1, 4} // Subset/superset checks new Set([2, 3]).isSubsetOf(a); // true a.isSupersetOf(new Set([2, 3])); // true // Disjoint check — no common elements new Set([5, 6]).isDisjointFrom(a); // true
All Set methods return new Set instances and do not modify the originals. They accept any set-like object as an argument — any object with size, has(), and keys() (e.g., other Sets, Maps).
Common Pitfalls
- Using objects as Map keys and expecting equality:
map.get({})won't findmap.set({}, value)(different object references). - Forgetting Map preserves insertion order: Unlike plain objects in older engines.
- Expecting Set methods like filter/map: Sets don't have these; convert to array first.
Best Practices
- Use Map when keys aren't strings: Or when key type matters.
- Use Set for uniqueness: Instead of array + includes() checks.
- Use WeakMap for object metadata: Allows garbage collection.
- Convert Set to Array for transformations:
[...set].map(...).
Summary
Maps store key-value pairs with any key type and maintain insertion order. Sets store unique values and are perfect for deduplication. Both are iterable and have .size property. Use WeakMap/WeakSet when you don't want to prevent garbage collection of keys.
Code Examples
const map = new Map();
// Set and get
map.set('name', 'Alice');
map.set(1, 'one'); // Number as key
map.set({ id: 1 }, 'user'); // Object as key
map.get('name'); // 'Alice'
map.get(1); // 'one'
// Size and existence
map.size; // 3
map.has('name'); // true
// Delete
map.delete('name');
map.clear(); // Remove allconst map = new Map([
['a', 1],
['b', 2],
['c', 3]
]);
// Iterate entries
for (const [key, value] of map) {
console.log(key, value);
}
// Other iterators
map.keys(); // Iterator of keys
map.values(); // Iterator of values
map.entries(); // Iterator of [key, value]
// forEach
map.forEach((value, key) => console.log(key, value));