JavaScript Map, Set, WeakMap, and WeakSet: Complete Guide
JavaScript gives you four related collection types for storing data: Map, Set, WeakMap, and WeakSet. They solve common problems that plain objects and arrays do not handle cleanly, such as fast key lookups, unique values, and object-only metadata.
Quick answer: Use Map for key-value pairs, Set for unique values, WeakMap for private object-linked data, and WeakSet for tracking objects without preventing garbage collection.
Difficulty: Beginner to Intermediate
You'll understand this better if you know: basic JavaScript variables, objects, arrays, and how functions work with references.
1. What Are Map, Set, WeakMap, and WeakSet?
These are built-in collection objects that store groups of values in ways that are more specialized than arrays and plain objects.
- Map stores key-value pairs and remembers insertion order.
- Set stores unique values with no duplicates.
- WeakMap stores key-value pairs where keys must be objects.
- WeakSet stores unique objects only.
Unlike plain objects, Map can use any value as a key, including objects and functions. Unlike arrays, Set automatically prevents duplicates.
2. Why These Collections Matter
These types make code clearer, safer, and often faster for the right task. They are especially useful when you need predictable iteration order, object-based keys, or uniqueness checks without writing extra logic.
They also help you avoid fragile patterns such as using array scans for lookups or manually simulating a set with an object.
3. Basic Syntax or Core Idea
Creating a Map
A Map starts empty unless you pass initial entries. Each entry is a two-item array: a key and a value.
const prices = new Map([
["apple", 1.25],
["banana", 0.75]
]);This creates a map with two entries. You can read and update entries with get and set.
Creating a Set
A Set stores values directly. If you add the same value again, it is ignored.
const tags = new Set(["js", "html", "js"]);This set ends up with only two values because duplicates are removed automatically.
Creating WeakMap and WeakSet
WeakMap and WeakSet only accept objects as references.
const user = { name: "Ava" };
const privateData = new WeakMap();
privateData.set(user, { token: "abc123" });This pattern is useful when you want data attached to an object without exposing that data through normal properties.
4. Step-by-Step Examples
Example 1: Looking up values with Map
Use a map when you want a direct association between keys and values. This is better than searching through an array of pairs.
const userRoles = new Map();
userRoles.set("alice", "admin");
userRoles.set("bob", "editor");
console.log(userRoles.get("alice")); // adminThe get method returns the stored value for a key, or undefined if the key is missing.
Example 2: Removing duplicates with Set
A set is an easy way to remove duplicates from a list of values.
const ids = [101, 102, 101, 103, 102];
const uniqueIds = [...new Set(ids)];
console.log(uniqueIds); // [101, 102, 103]The spread operator turns the set back into an array after duplicates are removed.
Example 3: Tracking object state with WeakMap
Weak maps are ideal for storing metadata about objects without attaching visible properties to them.
const stateByElement = new WeakMap();
function markSelected(element) {
stateByElement.set(element, { selected: true });
}Because the key is an object, the stored state can disappear automatically when the object is no longer referenced elsewhere.
Example 4: Checking membership with Set
Sets make membership checks easy and expressive.
const blockedWords = new Set(["spam", "ads", "promo"]);
function containsBlockedWord(text) {
return [...blockedWords].some(word => text.includes(word));
}This example shows a practical use of a set as a fast source of unique tokens.
5. Practical Use Cases
- Use Map for caches, lookup tables, and counted data.
- Use Set for selected IDs, unique tags, and membership filters.
- Use WeakMap for private per-object metadata, especially in libraries.
- Use WeakSet for tracking whether an object has been seen or processed.
- Use Map when keys are not simple strings, such as DOM nodes, dates, or function references.
6. Common Mistakes
Mistake 1: Using a plain object when keys are not strings
A plain object converts property keys to strings, which can cause collisions or unexpected behavior when you need object keys.
Problem: This code looks like it stores a value by object, but both keys become the same string representation.
const objKey1 = { id: 1 };
const objKey2 = { id: 2 };
const store = {};
store[objKey1] = "first";
store[objKey2] = "second";Fix: Use a Map when the key is an object or any non-string value.
const store = new Map();
store.set(objKey1, "first");
store.set(objKey2, "second");The map keeps the two object keys separate because it compares object identity, not string labels.
Mistake 2: Expecting Set to accept duplicates
Sets are built to enforce uniqueness. If you need duplicate values, an array is the right choice.
Problem: This code adds the same value more than once, but the set keeps only one copy.
const numbers = new Set();
numbers.add(5);
numbers.add(5);
numbers.add(5);
console.log(numbers.size); // 1Fix: Use an array if repeated values are meaningful, or keep Set if uniqueness is the goal.
const numbers = [5, 5, 5];
console.log(numbers.length); // 3The corrected version works because arrays preserve every entry instead of enforcing uniqueness.
Mistake 3: Using primitives as WeakMap or WeakSet keys
WeakMap and WeakSet only accept objects. If you use a string, number, or boolean, JavaScript throws a type error.
Problem: The key is not an object, so the runtime cannot store it in a weak collection.
const cache = new WeakMap();
cache.set("user-1", { loggedIn: true });Fix: Use an object key, or use a regular Map if your key is primitive.
const cache = new Map();
cache.set("user-1", { loggedIn: true });This works because Map allows primitive keys, while WeakMap does not.
7. Best Practices
Practice 1: Use Map for dynamic key sets
If you do not know the keys ahead of time, Map is usually clearer than an object.
const sessions = new Map();
sessions.set("abc", { userId: 42 });This makes the intent explicit: you are storing keyed records, not object properties.
Practice 2: Use Set to express uniqueness, not filtering after the fact
If the goal is unique values, let Set enforce it instead of deduplicating manually.
const seenEmails = new Set();
function addEmail(email) {
if (!seenEmails.has(email)) {
seenEmails.add(email);
}
}This approach is easier to read and avoids repeated array scans.
Practice 3: Prefer WeakMap for private metadata on objects
If library code needs to associate hidden state with objects, WeakMap avoids mutating the object itself.
const privateState = new WeakMap();
function createAccount(name) {
const account = { name };
privateState.set(account, { createdAt: new Date() });
return account;
}This keeps internal state separate from public data and supports garbage collection when the object is discarded.
8. Limitations and Edge Cases
- Map preserves insertion order, but key equality for objects is by reference, not by deep comparison.
- Set treats NaN values as the same value, so multiple NaN entries collapse into one.
- WeakMap and WeakSet are not iterable, so you cannot loop through all entries or values.
- WeakMap does not expose size, because entries may disappear when keys are garbage-collected.
- WeakSet can only tell you whether an object is present; it does not store reusable data.
- JSON serialization does not preserve Map or Set directly; you usually need to convert them first.
9. Practical Mini Project
Let’s build a simple tag manager that deduplicates tags and counts how many times each tag appears. This combines a set-like uniqueness rule with a map for counts.
const posts = [
["js", "web", "js"],
["css", "web"],
["js", "node"]
];
const allTags = new Set();
const tagCounts = new Map();
for (const tagList of posts) {
for (const tag of tagList) {
allTags.add(tag);
tagCounts.set(
tag,
(tagCounts.get(tag) || 0) + 1
);
}
}
console.log([...allTags]);
console.log(Object.fromEntries(tagCounts));This mini project shows two common patterns together: use Set for unique labels and Map for counting or lookup.
10. Key Points
- Map is for key-value storage with any key type.
- Set is for unique values and membership checks.
- WeakMap and WeakSet only work with object references.
- Weak collections do not prevent garbage collection of unused objects.
- Choose the collection based on the problem, not just on familiarity with arrays or objects.
11. Practice Exercise
- Create a Set from the array ["red", "blue", "red", "green", "blue"] and convert it back to an array.
- Build a Map that stores a score for each player name in a game.
- Use a WeakMap to attach private settings to an object representing a user profile.
Expected output: an array of unique colors, a retrievable score table, and private object-linked settings.
Hint: Remember that Set removes duplicates automatically, while Map uses set and get.
Solution:
const colors = ["red", "blue", "red", "green", "blue"];
const uniqueColors = [...new Set(colors)];
const scores = new Map();
scores.set("Mia", 12);
scores.set("Noah", 18);
const profile = { id: 7 };
const privateSettings = new WeakMap();
privateSettings.set(profile, { theme: "dark" });
console.log(uniqueColors);
console.log(scores.get("Mia"));
console.log(privateSettings.get(profile));12. Final Summary
Map, Set, WeakMap, and WeakSet are specialized JavaScript collections that solve problems common arrays and plain objects handle awkwardly. Use Map for flexible key-value storage, Set for uniqueness, and the weak variants when you need object-linked data that should not keep objects alive.
Knowing the difference between these structures helps you write code that is more expressive and less error-prone. If you use the right collection from the start, your intent becomes clearer and your implementations usually become simpler too.
Next, practice converting a few object-and-array-based data structures in your own code into Map or Set to see where the design improves.