Docs

6.3-Maps-and-Sets

6.3 Maps and Sets

Overview

ES6 introduced new built-in data structures: Map, Set, WeakMap, and WeakSet. These provide more efficient and specialized ways to store collections compared to plain objects and arrays.


Table of Contents

  1. •Map
  2. •Set
  3. •WeakMap
  4. •WeakSet
  5. •Comparison with Objects and Arrays
  6. •Use Cases and Patterns

Map

A Map holds key-value pairs where keys can be any type (including objects, functions, and primitives).

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                         Map                                  │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                             │
│   Key (any type)  ────►  Value (any type)                   │
│                                                             │
│   ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”           ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”                         │
│   │ {obj}   │  ───────► │ "data"  │                         │
│   ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤           ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤                         │
│   │ "name"  │  ───────► │ "Alice" │                         │
│   ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤           ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤                         │
│   │  123    │  ───────► │ [1,2,3] │                         │
│   ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜           ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜                         │
│                                                             │
│   • Maintains insertion order                               │
│   • Keys can be ANY type                                    │
│   • Has size property                                       │
│   • Iterable by default                                     │
│                                                             │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Creating and Using Maps

// Creating a Map
const map = new Map();

// Setting values
map.set('name', 'Alice');
map.set(1, 'one');
map.set(true, 'boolean key');

// Object as key (impossible with plain objects!)
const objKey = { id: 1 };
map.set(objKey, 'object value');

// Getting values
console.log(map.get('name')); // 'Alice'
console.log(map.get(objKey)); // 'object value'

// Checking existence
console.log(map.has('name')); // true
console.log(map.size); // 4

// Deleting
map.delete('name');

// Clearing all
map.clear();

Map Initialization

// Initialize with array of key-value pairs
const map = new Map([
  ['name', 'Alice'],
  ['age', 30],
  ['city', 'NYC'],
]);

// From Object.entries()
const obj = { a: 1, b: 2, c: 3 };
const mapFromObj = new Map(Object.entries(obj));

// Convert Map back to Object
const backToObj = Object.fromEntries(map);

Iterating Maps

const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3],
]);

// for...of (default: entries)
for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}

// Keys only
for (const key of map.keys()) {
  console.log(key);
}

// Values only
for (const value of map.values()) {
  console.log(value);
}

// forEach
map.forEach((value, key) => {
  console.log(`${key}: ${value}`);
});

Set

A Set stores unique values of any type.

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                         Set                                  │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                             │
│   ā”Œā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”                           │
│   │  1  │  2  │ "a" │ {x} │ fn  │  ← All unique values      │
│   ā””ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”˜                           │
│                                                             │
│   • No duplicate values allowed                             │
│   • Maintains insertion order                               │
│   • Values can be any type                                  │
│   • Fast lookup with has()                                  │
│                                                             │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Creating and Using Sets

// Creating a Set
const set = new Set();

// Adding values
set.add(1);
set.add(2);
set.add(2); // Duplicate - ignored!
set.add('hello');
set.add({ id: 1 });

console.log(set.size); // 4 (not 5!)

// Checking existence
console.log(set.has(1)); // true
console.log(set.has('hello')); // true

// Deleting
set.delete(1);

// Clearing
set.clear();

Set Initialization and Array Conversion

// Initialize with array
const set = new Set([1, 2, 3, 3, 4, 4, 5]);
console.log([...set]); // [1, 2, 3, 4, 5] - duplicates removed!

// Remove duplicates from array (common pattern!)
const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4]

// Convert Set to Array
const setToArray = Array.from(set);

Set Operations

const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);

// Union
const union = new Set([...setA, ...setB]);
// Set {1, 2, 3, 4, 5, 6}

// Intersection
const intersection = new Set([...setA].filter((x) => setB.has(x)));
// Set {3, 4}

// Difference (A - B)
const difference = new Set([...setA].filter((x) => !setB.has(x)));
// Set {1, 2}

// Symmetric Difference
const symDiff = new Set([
  ...[...setA].filter((x) => !setB.has(x)),
  ...[...setB].filter((x) => !setA.has(x)),
]);
// Set {1, 2, 5, 6}

WeakMap

A WeakMap is a Map where keys must be objects and are held "weakly" (can be garbage collected).

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                       WeakMap                                │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                             │
│   • Keys MUST be objects (not primitives)                   │
│   • Keys are weakly held (GC can collect them)              │
│   • NOT iterable (no forEach, keys, values, entries)        │
│   • No size property                                        │
│   • Perfect for private data / metadata                     │
│                                                             │
│   Only methods: get(), set(), has(), delete()               │
│                                                             │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

WeakMap Usage

const weakMap = new WeakMap();

let obj = { name: 'Alice' };
weakMap.set(obj, 'some private data');

console.log(weakMap.get(obj)); // 'some private data'
console.log(weakMap.has(obj)); // true

// When obj is no longer referenced elsewhere,
// both the key and value can be garbage collected
obj = null; // WeakMap entry becomes eligible for GC

// These DON'T work with WeakMap:
// weakMap.size        āŒ
// weakMap.keys()      āŒ
// weakMap.forEach()   āŒ

Private Data Pattern with WeakMap

// Store private data for class instances
const privateData = new WeakMap();

class User {
  constructor(name, password) {
    this.name = name;
    // Store password privately
    privateData.set(this, { password });
  }

  checkPassword(pwd) {
    return privateData.get(this).password === pwd;
  }
}

const user = new User('Alice', 'secret123');
console.log(user.name); // 'Alice'
console.log(user.password); // undefined (private!)
console.log(user.checkPassword('secret123')); // true

WeakSet

A WeakSet is a Set where values must be objects and are held weakly.

const weakSet = new WeakSet();

let obj1 = { id: 1 };
let obj2 = { id: 2 };

weakSet.add(obj1);
weakSet.add(obj2);

console.log(weakSet.has(obj1)); // true

obj1 = null; // obj1 becomes eligible for GC

// Only methods: add(), has(), delete()
// NOT iterable, no size property

WeakSet Use Cases

// Track visited objects (e.g., deep clone)
const visited = new WeakSet();

function deepClone(obj) {
  if (visited.has(obj)) {
    throw new Error('Circular reference detected');
  }
  visited.add(obj);
  // ... clone logic
}

// Mark objects as "processed"
const processed = new WeakSet();

function processOnce(obj) {
  if (processed.has(obj)) return;
  processed.add(obj);
  // Process obj...
}

Comparison

FeatureObjectMapWeakMap
Key typesString/SymbolAnyObjects only
Key orderNot guaranteedInsertion orderN/A
SizeManual count.sizeN/A
IterableYes (keys)YesNo
GC of keysNoNoYes
PerformanceGoodBetter for frequent add/deleteGood
FeatureArraySetWeakSet
DuplicatesAllowedNot allowedNot allowed
Value typesAnyAnyObjects only
OrderIndex-basedInsertion orderN/A
LookupO(n)O(1)O(1)
IterableYesYesNo

Use Cases

When to Use Map

// 1. Non-string keys needed
const userPermissions = new Map();
userPermissions.set(userObject, ['read', 'write']);

// 2. Frequent additions/deletions
const cache = new Map();

// 3. Need to maintain insertion order
const orderedConfig = new Map();

// 4. Need size property
console.log(map.size);

When to Use Set

// 1. Remove duplicates
const unique = [...new Set(array)];

// 2. Fast membership testing
const allowedIds = new Set([1, 2, 3, 4, 5]);
if (allowedIds.has(userId)) {
  /* allowed */
}

// 3. Mathematical set operations
// Union, intersection, difference

When to Use WeakMap/WeakSet

// 1. Caching computed values for objects
const cache = new WeakMap();
function expensiveOperation(obj) {
    if (cache.has(obj)) return cache.get(obj);
    const result = /* compute */;
    cache.set(obj, result);
    return result;
}

// 2. Storing private/metadata
// 3. Tracking object references without preventing GC

Summary

StructureUse When
MapNeed non-string keys, ordered pairs, or frequent add/remove
SetNeed unique values, fast lookup, or set operations
WeakMapNeed object keys with automatic cleanup
WeakSetNeed to track objects without preventing GC

Next Steps

  • •Learn about TypedArrays for binary data (6.4)
  • •Explore Proxy and Reflect for metaprogramming (10.7)
.3 Maps And Sets - JavaScript Tutorial | DeepML