Ad – 728Γ—90
πŸ“¦ Data Structures

JavaScript Map and Set – Modern Data Collections

ES6 introduced Map and Set as purpose-built alternatives to plain objects and arrays. A Map stores ordered key-value pairs where keys can be any type; a Set stores unique values with no duplicates. Knowing when to use each over the built-in alternatives is a hallmark of experienced JavaScript developers.

⏱️ 22 min read 🎯 Intermediate πŸ“… Updated 2026

Map Basics

A Map is an ordered collection of key-value pairs. Unlike a plain object, Map keys can be any value β€” including objects, functions, or primitives β€” and insertion order is preserved.

JavaScript
// Create a Map
const map = new Map();

// set(key, value) – add or update entries
map.set('name', 'Alice');
map.set(42, 'the answer');
map.set(true, 'boolean key');

const objKey = { id: 1 };
map.set(objKey, 'object as key'); // objects can be keys!

// get(key) – retrieve a value
console.log(map.get('name'));    // 'Alice'
console.log(map.get(42));        // 'the answer'
console.log(map.get(objKey));    // 'object as key'
console.log(map.get('missing')); // undefined

// has(key) – check existence
console.log(map.has(true));      // true
console.log(map.has('absent'));  // false

// size – number of entries (not .length)
console.log(map.size); // 4

// delete(key) – remove one entry
map.delete(42);
console.log(map.size); // 3

// clear() – remove all entries
// map.clear();

// Initialize from array of pairs
const roles = new Map([
  ['Alice', 'admin'],
  ['Bob', 'editor'],
  ['Carol', 'viewer']
]);

Iterating a Map

JavaScript
const scores = new Map([
  ['Alice', 95],
  ['Bob', 82],
  ['Carol', 88]
]);

// for...of with destructuring (most common)
for (const [name, score] of scores) {
  console.log(`${name}: ${score}`);
}

// forEach
scores.forEach((value, key) => {
  console.log(`${key} scored ${value}`);
});

// keys(), values(), entries()
console.log([...scores.keys()]);    // ['Alice', 'Bob', 'Carol']
console.log([...scores.values()]);  // [95, 82, 88]
console.log([...scores.entries()]); // [['Alice', 95], ['Bob', 82], ...]

// Convert Map β†’ Array of objects
const arr = Array.from(scores, ([name, score]) => ({ name, score }));
// [{ name: 'Alice', score: 95 }, ...]

// Convert plain object β†’ Map
const obj = { x: 1, y: 2 };
const mapFromObj = new Map(Object.entries(obj));
console.log(mapFromObj.get('x')); // 1
β–Ά Output
Alice: 95
Bob: 82
Carol: 88
Alice scored 95
...
['Alice', 'Bob', 'Carol']
[95, 82, 88]

Map vs Object Comparison

FeatureMapPlain Object
Key typesAny value (objects, functions, primitives)String or Symbol only
Key orderInsertion order guaranteedInsertion order (mostly, ES2015+)
Sizemap.sizeMust compute with Object.keys().length
Prototype pollutionNo inherited keysInherits from Object.prototype
SerialisationNot directly JSON-serialisableWorks with JSON.stringify
PerformanceBetter for frequent add/removeBetter for static structures
Best forDynamic key-value stores, any-key-typeStructured data, configs, DTOs

Set Basics

A Set stores a collection of unique values in insertion order. Adding an already-present value has no effect.

JavaScript
const set = new Set();

// add(value)
set.add(1);
set.add(2);
set.add(2); // duplicate – silently ignored
set.add('hello');
set.add({ id: 1 }); // different object reference β†’ added

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

// has(value)
console.log(set.has(2));       // true
console.log(set.has('world')); // false

// delete(value)
set.delete(1);
console.log(set.size); // 3

// Initialize from array (automatic deduplication!)
const unique = new Set([1, 2, 2, 3, 3, 3, 4]);
console.log(unique.size); // 4

// Set deduplication pattern (most common use case)
const numbers = [1, 2, 2, 3, 3, 4];
const deduped = [...new Set(numbers)];
console.log(deduped); // [1, 2, 3, 4]

// Deduplicate strings
const tags = ['js', 'html', 'js', 'css', 'html'];
const uniqueTags = [...new Set(tags)];
console.log(uniqueTags); // ['js', 'html', 'css']

Iterating a Set

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

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

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

// Convert to Array
const arr = [...colors];         // spread
const arr2 = Array.from(colors); // Array.from

// Set operations (manual implementations)
const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);

// Union
const union = new Set([...a, ...b]);
console.log([...union]); // [1, 2, 3, 4, 5, 6]

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

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

WeakMap and WeakSet

The WeakMap and WeakSet variants hold weak references, meaning they do not prevent garbage collection of their keys/values. They are non-iterable and their primary use case is associating metadata with objects without creating memory leaks.

JavaScript
// WeakMap – keys must be objects; values can be anything
const cache = new WeakMap();

function process(obj) {
  if (cache.has(obj)) {
    return cache.get(obj); // return cached result
  }
  const result = /* expensive computation */ { computed: true };
  cache.set(obj, result);
  return result;
}

let domNode = document.getElementById('app');
cache.set(domNode, { clicks: 0 });
// If domNode is set to null and removed from DOM,
// the WeakMap entry is garbage-collected automatically

// WeakSet – stores objects (no primitives), weak references
const seen = new WeakSet();
function visitOnce(obj) {
  if (seen.has(obj)) return 'already visited';
  seen.add(obj);
  return 'first visit';
}

// Key differences from Map/Set:
// - Keys/values must be objects (WeakMap keys, WeakSet values)
// - Not iterable (no forEach, no for...of, no .size)
// - Automatically cleaned up when references are lost
πŸ’‘
When to Use WeakMap

Use WeakMap when you want to attach private data or metadata to an object without interfering with garbage collection. Common patterns: caching DOM-related data, storing private instance data in class implementations, and memoisation caches keyed by object identity.

πŸ’‘
Choose the Right Collection

Use Set to deduplicate values or track membership. Use Map when you need non-string keys or need to frequently add/delete entries. Use a plain object for static, string-keyed structured data that needs JSON serialisation.

Interview Questions

  • What is the difference between a Map and a plain object?
  • How would you deduplicate an array using a Set?
  • Why can't you iterate a WeakMap or WeakSet?
  • How do you convert a Map to a plain object and back?
  • Implement a Set intersection using the spread operator.

πŸ‹οΈ Practical Exercise

Given an array of log entries where each entry is { userId, action, timestamp }:

  1. Use a Map to count how many actions each user performed.
  2. Use a Set to find the unique actions that were performed.
  3. Log both results in a readable format.

πŸ”₯ Challenge Exercise

Implement a LRUCache class using a Map (which preserves insertion order). The cache should accept a capacity in the constructor and implement get(key) (returns -1 if not found, and moves the key to most-recently-used) and put(key, value) (evicts the least-recently-used item if capacity is exceeded).

Frequently Asked Questions

Does a Map preserve insertion order?
Yes. Map iterates entries in the order they were inserted, which is part of the specification. Plain objects also follow insertion order for string keys in most modern engines, but this is not as strictly guaranteed for numeric-like keys.
Can a Set contain NaN?
Yes. Set uses the SameValueZero algorithm for equality. While NaN !== NaN in regular comparisons, a Set treats all NaN values as equal, so only one NaN can be stored.
Why use Map over an object for a dictionary?
A Map does not have prototype keys that can collide (e.g., 'constructor', 'toString'), supports any key type, and has a built-in size property. These make it safer and more predictable for dynamic key-value storage.
How do I convert a Set to an array?
Use spread: [...mySet] or Array.from(mySet). Both produce a regular array in insertion order.
Is WeakRef related to WeakMap?
They are related conceptually β€” both allow weak references. WeakRef (ES2021) lets you hold a weak reference to any object and check if it has been garbage-collected, while WeakMap/WeakSet automatically clean up their entries.
Ad – 336Γ—280

πŸ“‹ Summary

  • Map stores ordered key-value pairs with any key type and a reliable .size property.
  • Prefer Map over objects when keys are dynamic, non-string, or frequently added/removed.
  • Set stores unique values in insertion order; perfect for deduplication and membership tests.
  • Use [...new Set(arr)] as a concise one-liner to remove array duplicates.
  • Set operations (union, intersection, difference) are easy with spread and filter/has.
  • WeakMap and WeakSet hold weak references β€” they do not prevent garbage collection and are not iterable.
  • Use WeakMap for attaching private metadata to objects without memory leaks.