Home/Learn/JavaScript & TypeScript/Map & Set — When a Plain Object Is Not Enough

Map & Set — When a Plain Object Is Not Enough

Intermediate
Working with Data

Map allows any value as a key and preserves insertion order; Set stores unique values. Both are the right answer more often than the object-as-dictionary habit suggests.

Overview

For years the only dictionary was a plain object, which forces every key to a string and mixes your data with inherited properties. Map and Set fixed that. Map takes any key including objects and functions, keeps insertion order, reports its size directly, and iterates without prototype surprises. Set gives uniqueness and O(1) membership testing, which turns a common O(n²) filter into O(n). Both also have weak variants that do not prevent garbage collection.

Map vs Object

Use a Map when keys are not fixed strings known at author time, or when you need order and size.

Any key type, real size, insertion order
const cache = new Map()

cache.set('key', value)
cache.set(userObject, metadata)     // an object as a key — impossible with {}
cache.get('key')
cache.has('key')                    // no prototype confusion
cache.delete('key')
cache.size                          // a property, not Object.keys().length

for (const [k, v] of cache) { ... } // insertion order, guaranteed

// The object trap Map avoids:
const obj = {}
obj[1] = 'a'; obj['1'] = 'b'
Object.keys(obj)          // ['1'] — the number became a string

const map = new Map()
map.set(1, 'a').set('1', 'b')
map.size                  // 2 — distinct keys

Set for Uniqueness and Membership

The most common use is deduplication, and the second most common is turning a repeated .includes() into a fast lookup.

Dedupe, and O(1) membership
// Deduplicate
const unique = [...new Set([1, 2, 2, 3])]      // [1, 2, 3]

// Fast membership — this is the important one
const allowed = new Set(['admin', 'editor'])
allowed.has(role)            // O(1)

// vs the O(n) version inside a loop — O(n*m) overall
users.filter(u => allowedArray.includes(u.role))
users.filter(u => allowed.has(u.role))          // O(n)

// Set operations
const a = new Set([1, 2, 3]), b = new Set([2, 3, 4])
const intersection = [...a].filter(x => b.has(x))    // [2, 3]
const difference   = [...a].filter(x => !b.has(x))   // [1]

WeakMap and WeakSet

Weak collections hold keys weakly, so an entry does not stop its key being garbage collected. Used for attaching data to objects you do not own.

WeakMap, and the leak it prevents
const metadata = new WeakMap()

function tag(element, info) {
  metadata.set(element, info)     // when element is removed from the DOM
}                                 // and dereferenced, the entry goes too

// A normal Map here would leak: it holds a strong reference,
// so every element you ever tagged stays in memory forever.

// Constraints: keys must be objects, and they are not iterable
// (you cannot list the contents — that is what makes collection safe).

Key Points to Remember

  • 1Map accepts any value as a key; object keys are always coerced to strings
  • 2Map preserves insertion order, exposes .size, and iterates without prototype pollution
  • 3Set gives O(1) membership — replacing .includes() inside a loop turns O(n*m) into O(n)
  • 4[...new Set(arr)] is the idiomatic deduplication
  • 5WeakMap holds keys weakly so entries do not prevent garbage collection — use it to attach data to DOM nodes

Interview Questions

Sign in to ask Aria
1

When would you use a Map instead of a plain object?

Medium
2

How do you remove duplicates from an array?

Easy
3

What problem does WeakMap solve that Map cannot?

Hard

Ask Aria about Map & Set — When a Plain Object Is Not Enough

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…