JGJonathan Gobielweb platform engineer
Back

javascript set vs array map vs object

Stop Defaulting to Objects and Arrays: When Set and Map Deliver Cleaner Code and 2x to 10x Lookup Wins

3 min readSource

Most JavaScript codebases use Object and Array as default containers for almost everything.

That is fine until lookup frequency rises, key types vary, and deduplication logic turns into a pile of helper functions.

Set and Map were designed for these exact cases.

TL;DR

  • Use Set for uniqueness and membership checks.
  • Use Map for dynamic key-value storage with non-string keys.
  • Keep Array for ordered sequences and transforms.
  • Keep plain object for fixed schema data and JSON boundaries.

Why This Matters in Real Apps

The wrong container often passes code review because behavior is still correct.

Performance and readability debt appears later:

  • repeated array.includes() in hot loops,
  • object key coercion edge cases,
  • custom dedupe utilities everywhere.

Your reference highlights real-world gains of 2x to 10x in some large lookup-heavy flows when moving from arrays to sets.

That range is plausible when membership checks dominate runtime.

Set for Membership and Deduplication

const ids = new Set([1, 2, 2, 3])

console.log(ids.size) // 3
console.log(ids.has(2)) // true

Why Set helps:

  • no duplicates by definition,
  • expected O(1) has lookup,
  • cleaner intent for visited-node tracking, tags, and ID filters.

Comparison:

  • set.has(value) is expected O(1),
  • array.includes(value) is O(n) worst-case.

If that check runs inside another loop, complexity pain compounds quickly.

Map for Dynamic Keys and Predictable Iteration

const userSessions = new Map<object, string>()
const user = { id: 1 }

userSessions.set(user, "active")
console.log(userSessions.get(user)) // active

Why Map helps:

  • keys can be objects, functions, numbers, symbols,
  • insertion order is preserved,
  • API (set/get/has/delete) makes key-value intent explicit.

Map is especially useful for caches, metadata registries, and dependency graphs where key type is not always string.

Where Object and Array Still Win

Object and Array are not obsolete.

Use object when:

  • data shape is fixed,
  • serialization to JSON is required,
  • ergonomics of literal syntax matter.

Use array when:

  • order matters,
  • you need sequence transforms (map/filter/reduce),
  • index-based access is meaningful.

The key is not replacing everything.

The key is matching data structure to dominant access pattern.

Migration Tactics Without Breaking APIs

You can modernize internals and preserve external contracts.

const roleMap = new Map<number, string>([
  [1, "admin"],
  [2, "viewer"],
])

const rolesAsObject = Object.fromEntries(roleMap.entries())

This gives internal correctness and external compatibility.

What We Usually Try First and Why It Fails

Teams often micro-optimize loops before fixing data model choices.

That is backwards.

If a workload is membership-heavy, changing the container usually yields larger gains than minor loop-level refactors.

Practical Selection Checklist

  1. Is this mostly membership checking? Use Set.
  2. Are keys dynamic or non-string? Use Map.
  3. Is this ordered sequence processing? Use Array.
  4. Is this fixed schema for JSON payloads? Use Object.
  5. Is the path hot? Benchmark before and after.

FAQ

Is Set always faster than Array?

Not for every operation.

Set is strong for membership checks. Arrays remain strong for ordered iteration and transform chains.

Is Map always better than Object?

No.

Map is better for dynamic keys and key operation semantics. Object is often simpler for fixed schema payloads.

Can I store object keys in plain object safely?

Not in the same way as Map.

Object keys are coerced to strings, which can produce collisions and surprising behavior.

Should I migrate everything now?

No.

Start with hotspot paths where lookup complexity is visible in profiling.

Closing

Data structure choice is architecture, not style preference.

If your app does frequent lookups or dynamic keying, Set and Map can reduce both cognitive load and runtime cost with surprisingly small refactors.