Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

When is a `Map` more useful than a plain JavaScript object?

Quick answer

Use a Map when your lookup is built dynamically, its keys may be values other than strings, or you want convenient entry counting and insertion-order iteration. Use a plain object when you are representing a known set of named fields, such as a configuration record. A Map supports any value as a key, exposes .size, and works directly with for...of; object keys are strings or symbols, and objects are not directly iterable that way by default. [S1][S2]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I’m building a lookup table as my program runs. When is Map a better fit than a plain object?

Geez

A Map is especially useful when you do not know all the keys in advance, or when a key might be something other than a string. For example, you could associate each object representing a user session with data for that session. A Map accepts keys of any value, including objects and primitives; an ordinary object uses string or symbol keys. [S1][S2]

An object is usually clearer for a fixed-shape record whose fields are known and named ahead of time, such as { theme: "dark", language: "en" }. MDN describes this as a useful distinction: dynamic lookup keys favor considering Map, while known string-keyed data shapes fit ordinary objects naturally. [S1]

So the practical question is: are these named fields in a record, or entries in a lookup that grows and changes?

Follow-up question

Can you show a small example that adds entries, retrieves one, and loops over them?

Geez

Here is a small example using made-up values. The object key is deliberately reused so retrieval asks for the exact same key:

const north = { name: "North" };
const prices = new Map();

prices.set(north, 12);
prices.set("standard", 8);

console.log(prices.get(north)); // 12
console.log(prices.size);       // 2

for (const [key, value] of prices) {
  console.log(key, value);
}

set(key, value) stores an entry, get(key) retrieves its value, and .size reports the number of entries. Iterating a Map with for...of yields [key, value] pairs in insertion order. [S2]

For object keys, identity matters: north retrieves the entry because it is the same object used when setting it. A separately created object such as { name: "North" } is not the same key, even though its contents look alike. [S2]

Follow-up question

What would the equivalent plain-object approach look like, and what do I give up?

Geez

For a fixed record, an object makes the named fields easy to read:

const settings = {
  theme: "dark",
  language: "en"
};

console.log(settings.theme);

That shape is a good fit when theme and language are the known fields you intend to store. But it is not a direct replacement for the earlier Map: ordinary object keys are strings or symbols, and an object is not directly iterable with for...of by default. [S1][S2]

With a Map, the entry count is available as .size, and the entries can be traversed directly as pairs. With an object, you can still enumerate properties using other approaches, but that is a different interface. Choose based on the shape and behavior you want rather than assuming one container is always faster; the cited documentation does not establish a universal performance winner. [S2]

Follow-up question

How can I make the choice quickly when I’m writing the code?

Geez

Use this short decision guide:

  1. If the data is a record with a known set of string-named fields, start with a plain object.
  2. If entries arrive dynamically, keys might be objects or other non-string values, or you want direct insertion-order iteration and .size, consider Map. [S1][S2]
  3. If you use objects as Map keys, keep and reuse the same object reference when retrieving the entry. Equal-looking objects are not interchangeable keys. [S2]

For example, a fixed app preference record is naturally expressed as an object; a lookup associating changing runtime objects with values is a natural case to evaluate for Map. This is a choice about data shape and access patterns, not a claim that every lookup needs a Map.

A practical checklist

  • List whether your keys are known named fields or are created at runtime.

  • Check whether any key needs to be an object or another non-string value.

  • Choose an object for a fixed, clearly named record; consider Map for a changing lookup.

  • If choosing Map, use .set() to add entries, .get() to retrieve them, and .size to count them.

  • When iterating a Map, use for...of to receive each [key, value] pair in insertion order.

  • For object keys in a Map, retain the original reference for later retrieval.

A few more useful answers

Does a `Map` treat two objects with identical properties as the same key?

No. Object keys are matched by identity, so you need the same object reference used when storing the entry. [S2]

Can I use `for...of` directly on a plain object?

Not by default. A Map is directly iterable with for...of and yields key-value pairs; ordinary objects are not directly iterable that way. [S1][S2]

Is `Map` always faster than an object?

The cited documentation does not establish a universal performance winner. Choose based on your keys, data shape, and need for entry counting or direct iteration. [S2]

Sources

References used for this guide.

  1. [S1] Keyed collections — JavaScript | MDN
    developer.mozilla.org · Checked
  2. [S2] Map — JavaScript | MDN
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work