ESC

Type to search the knowledge base.

Map and Set

Map for any-key dictionaries and Set for unique values — iteration order, object keys, Weak variants, and when objects/arrays still win.

beginner3 min read
  • javascript
  • map
  • set
  • collections

Plain objects and arrays cover a lot. Map and Set fix the sharp edges: object keys only stringify, accidental prototype keys, and slow “unique via indexOf” patterns. Prefer them when keys aren’t strings or when you need reliable collection semantics.

Map

const m = new Map();
m.set('n', 1);
m.set(1, 'one'); // number key ≠ '1'
m.set(true, 'yes');

const user = { id: 7 };
m.set(user, { roles: ['admin'] }); // object as key

m.get(user); // { roles: ['admin'] }
m.has('n'); // true
m.delete('n');
m.size; // count
const fromEntries = new Map([
  ['a', 1],
  ['b', 2],
]);

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

Map vs object

Object Map
Keys strings / symbols any value
Size manual .size
Iterate Object.* / for-in care for...of, .keys()
Prototype can collide (toString) no accidental keys
JSON natural need conversion
// object key footgun
const o = {};
o[user] = true; // key becomes "[object Object]"

// frequency map
function freq(str) {
  const map = new Map();
  for (const ch of str) map.set(ch, (map.get(ch) ?? 0) + 1);
  return map;
}

Set

const s = new Set([1, 2, 2, 3]);
s.size; // 3
s.add(4);
s.has(2); // true
s.delete(2);

// unique array
const unique = [...new Set(ids)];

// membership for objects — reference equality
const seen = new Set();
seen.add(user);
seen.has(user); // true
seen.has({ id: 7 }); // false
// set operations (manual)
function union(a, b) {
  return new Set([...a, ...b]);
}
function inter(a, b) {
  return new Set([...a].filter((x) => b.has(x)));
}
function diff(a, b) {
  return new Set([...a].filter((x) => !b.has(x)));
}

Modern engines also ship Set methods like union / intersection — check support or polyfill.

Iteration

map.keys();
map.values();
map.entries(); // default in for...of
set.values(); // same as keys for Set

// convert
Object.fromEntries(map); // string keys only really make sense
new Map(Object.entries(obj));

WeakMap / WeakSet (pointer)

Keys must be objects; entries don’t prevent GC. See WeakMap and WeakSet.

const wm = new WeakMap();
wm.set(element, { clicks: 0 });

When objects/arrays are still fine

  • JSON-shaped config with string keys → object
  • Ordered list with duplicates → array
  • Map when: unknown key types, frequent add/delete, need size, no prototype risk

Interview answer

“Map is a key→value collection with any keys and insertion-ordered iteration; Set stores unique values by SameValueZero. I use Map for frequency counts and object keys, Set for uniqueness and membership. Objects remain fine for simple string-key records and JSON. WeakMap/WeakSet allow GC of keys.”

Performance and key equality

// Map uses SameValueZero for keys — like Set
const m = new Map();
m.set(NaN, 'not-a-number');
m.get(NaN); // 'not-a-number'

// objects as keys are by reference
const a = { id: 1 };
const b = { id: 1 };
m.set(a, true);
m.has(b); // false

For “same user id” membership, store the id string/number in a Set, not the whole object, unless you control identity. Map/Set operations are amortized O(1); building a unique list via array.includes in a loop is O(n²). Prefer Set for dedupe of primitives on large inputs.

Further reading

Related guides