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

Creating a Map

A Map starts empty unless you pass initial entries. Each entry is a two-item array: a key and a value.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
const userRoles = new Map();
userRoles.set("alice", "admin");
userRoles.set("bob", "editor");

console.log(userRoles.get("alice")); // admin
Output✓ Tested · Node 24
admin

The 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.

JavaScript
const ids = [101, 102, 101, 103, 102];
const uniqueIds = [...new Set(ids)];

console.log(uniqueIds); // [101, 102, 103]
Output✓ Tested · Node 24
[ 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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
const numbers = new Set();
numbers.add(5);
numbers.add(5);
numbers.add(5);

console.log(numbers.size); // 1
Output✓ Tested · Node 24
1

Fix: Use an array if repeated values are meaningful, or keep Set if uniqueness is the goal.

JavaScript
const numbers = [5, 5, 5];

console.log(numbers.length); // 3
Output✓ Tested · Node 24
3

The 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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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.

JavaScript
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));
Output✓ Tested · Node 24
[ "js", "web", "css", "node" ]
{ js: 3, web: 2, css: 1, node: 1 }

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.

Show solution
JavaScript
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));
Output✓ Tested · Node 24
[ "red", "blue", "green" ]
12
{ theme: "dark" }

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.