# JavaScript Map, Set, WeakMap, and WeakSet: Complete Guide

Source: https://devdocs10.com/articles/javascript/js-maps-sets  
By Murat Bo · Published 2026-07-05 · DevDocs10 (https://devdocs10.com)

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 with Node 24.21.0):

```text
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 with Node 24.21.0):

```text
[ 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 with Node 24.21.0):

```text
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 with Node 24.21.0):

```text
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 with Node 24.21.0):

```text
[ "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`.

**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 with Node 24.21.0):

```text
[ "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.
