DEV Community

Mehedi Hasan
Mehedi Hasan

Posted on

Why Map Lookups Are Slower Than Object Lookups in JavaScript

Imagine this: you’re optimizing your JavaScript code and you notice something odd. You’re using a Map to store some configuration settings or feature flags, but when you benchmark it against a plain object, it feels slower.

Both Map and Object provide O(1) lookups, so what’s happening under the hood? Let’s break it down.

The Common Misconception

Many developers assume that Map is the modern, better alternative to Object for all key-value storage. And for certain cases, it absolutely is.

But here’s the thing: if your keys are strings and the set of keys is relatively small and fixed, an Object is almost always faster. Why? Let’s dive into the mechanics.

Objects vs. Maps: The Basics

Consider this scenario: you have a set of API endpoints your application uses.

// Using an Object
const endpoints = {
  login: '/api/login',
  logout: '/api/logout',
  profile: '/api/profile'
};

// Using a Map
const endpointsMap = new Map([
  ['login', '/api/login'],
  ['logout', '/api/logout'],
  ['profile', '/api/profile']
]);

Enter fullscreen mode Exit fullscreen mode

Accessing a value:

endpoints['login'];       // Object property access
endpointsMap.get('login'); // Map lookup

Enter fullscreen mode Exit fullscreen mode

On the surface, both do the same thing: give you the value for a key. But how they achieve it internally is different.

What Happens Under the Hood

Objects use hidden classes

Modern JavaScript engines, like V8, optimize objects heavily. When you create an object:

const endpoints = { login: '/api/login', logout: '/api/logout' };

Enter fullscreen mode Exit fullscreen mode
  • The engine builds a hidden class for the object — think of it as a lightweight blueprint, like a C struct.
  • Each property gets a fixed memory offset.
  • Accessing a property is basically a direct pointer lookup. Blazing fast.

Maps use generic hash tables

When you create a Map:

const endpointsMap = new Map([['login', '/api/login'], ['logout', '/api/logout']]);

Enter fullscreen mode Exit fullscreen mode
  • The engine can’t assume fixed property types.
  • Keys can be anything — strings, numbers, objects, even NaN.
  • Every .get() involves:
    1. Hashing the key.
    2. Finding the appropriate bucket.
    3. Comparing keys for equality.
  • Even though this is still O(1) on average, the constant factor is higher.

Seeing the Difference in a Benchmark

Let’s test it with a simple benchmark:

const obj = {
  login: '/api/login',
  logout: '/api/logout',
  profile: '/api/profile'
};

const map = new Map(Object.entries(obj));
const keys = ['login', 'logout', 'profile'];

console.time('Object');
for (let i = 0; i < 1e7; i++) obj[keys[i % 3]];
console.timeEnd('Object');

console.time('Map');
for (let i = 0; i < 1e7; i++) map.get(keys[i % 3]);
console.timeEnd('Map');

Enter fullscreen mode Exit fullscreen mode

Typical results on Node.js:

Object: 50 ms
Map:    180 ms
Enter fullscreen mode Exit fullscreen mode

Even though both are O(1), the object access is significantly faster in practice because of engine optimizations.

When Map Is Actually Better

That said, Map isn’t bad — it’s just optimized for different scenarios:

  • Non-string keys: Like objects or functions.
const userRoles = new Map();
userRoles.set(userObj, 'admin');

Enter fullscreen mode Exit fullscreen mode
  • Dynamic key sets: When keys are added or removed frequently.
  • Guaranteed iteration order: Maps preserve insertion order.
  • Large datasets with unknown keys: Maps scale better than objects when used as true hash tables.

Quick Comparison

Aspect Object Map
Key Types Strings / Symbols Any value
Lookup Speed Faster (hidden classes) Slower (hash + compare)
Memory Lower Higher
Dynamic Resizing Poor Excellent
Ideal Use Case Small, static, string-keyed data Dynamic or complex key-value pairs

TL;DR

  • Object lookups are JIT-optimized (hidden classes + inline caching).
  • Map lookups are generic hash table operations — flexible but slightly slower.
  • For small, fixed, string-keyed datasets → Object wins.
  • For dynamic or complex keys → Map shines.

Closing Thoughts

Sometimes, the “modern” API isn’t the fastest — it’s just more flexible.
Understanding what happens under the hood helps you write code that is both clean and performant.

So next time you reach for Map by default, ask yourself: do I really need its flexibility, or is a simple object enough?

Top comments (0)