Before ES6, JavaScript developers reached for plain objects as makeshift key-value stores and arrays as makeshift unique-value collections, working around their limitations by hand. Map and Set are purpose-built collection types that fix those limitations directly, with cleaner APIs and better performance for their specific use cases.
Map: A Proper Key-Value Collection
A Map stores key-value pairs, just like an object — but with real advantages: keys can be any type (not just strings/symbols), it keeps insertion order reliably, and it has a built-in .size instead of you having to compute Object.keys(obj).length.
const scores = new Map();
scores.set("alice", 95);
scores.set("bob", 87);
scores.set(42, "a numeric key"); // keys don't have to be strings
console.log(scores.get("alice")); // 95
console.log(scores.has("bob")); // true
console.log(scores.size); // 3
scores.delete("bob");
console.log(scores.size); // 2
// Iterating a Map (preserves insertion order)
for (const [key, value] of scores) {
console.log(key, "-", value);
}
Output:
95
true
3
2
alice - 95
42 - a numeric key
That last point — using 42 (a number) as a key — is something a plain object can't do cleanly; object keys are always coerced to strings.
Set: A Collection of Unique Values
A Set stores values with no duplicates — adding a value that already exists is silently a no-op. This replaces the common pattern of manually checking array.includes(value) before pushing.
const tags = new Set();
tags.add("javascript");
tags.add("python");
tags.add("javascript"); // ignored — already in the set
console.log(tags.size); // 2
console.log(tags.has("python")); // true
// A classic use: deduplicate an array in one line
const numbers = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3, 4]
Output:
2
true
[ 1, 2, 3, 4 ]
That [...new Set(array)] pattern is one of the most common one-liners in everyday JavaScript — converting the array to a Set drops duplicates automatically, and spreading it back into an array gives you the deduplicated result.
When to Reach for Each One
Use a Map instead of a plain object when your keys aren't simple strings, when key order matters and must be reliable, or when you're frequently adding/removing entries and want a real .size property rather than recomputing a length. Use a Set instead of an array when you need to guarantee uniqueness and care more about fast membership checks (.has() is much faster than .includes() on a large array) than about indexed access.
For everyday simple data — a small fixed set of named properties, like configuration — a plain object or array is usually still the more natural, readable choice.
