Progress9 of 20 topics

45% complete

JavaScript Maps and Sets

Maps and Sets are specialized collection types introduced in ES6 (ECMAScript 2015) that provide more powerful ways to handle collections of data. While arrays and objects can handle most collection needs, Maps and Sets offer unique features that make them better suited for certain scenarios.

When to Use Maps and Sets

Use Maps when you need:

  • A collection of key-value pairs where keys can be any data type (not just strings)
  • To frequently add and remove key-value pairs
  • To easily get the size of the collection
  • To maintain insertion order

Use Sets when you need:

  • A collection of unique values (no duplicates)
  • To quickly check if a value exists
  • To easily remove duplicates from an array
  • To maintain insertion order

JavaScript Sets

A Set is a collection of unique values. Each value can only occur once in a Set, making it perfect for eliminating duplicates and checking for value existence.

Creating a Set

JavaScript
1// Creating an empty Set
2let emptySet = new Set();
3
4// Creating a Set from an array
5let colors = new Set(['red', 'green', 'blue', 'red']); // Note: duplicate 'red' is ignored
6console.log(colors); // Set(3) {"red", "green", "blue"}
7
8// Creating a Set from a string
9let letters = new Set('hello');
10console.log(letters); // Set(4) {"h", "e", "l", "o"} (duplicate 'l' is ignored)
11
12// Adding values during initialization
13let numbers = new Set([1, 2, 3, 4, 5]);

Basic Set Operations

JavaScript
1let fruits = new Set();
2
3// Adding values
4fruits.add('apple');
5fruits.add('banana');
6fruits.add('orange');
7console.log(fruits); // Set(3) {"apple", "banana", "orange"}
8
9// Adding a duplicate (ignored)
10fruits.add('apple');
11console.log(fruits); // Still Set(3) {"apple", "banana", "orange"}
12
13// Checking if a value exists
14console.log(fruits.has('banana')); // true
15console.log(fruits.has('grape')); // false
16
17// Getting the size
18console.log(fruits.size); // 3
19
20// Removing a value
21fruits.delete('orange');
22console.log(fruits); // Set(2) {"apple", "banana"}
23
24// Clearing all values
25fruits.clear();
26console.log(fruits); // Set(0) {}

Iterating Through a Set

JavaScript
1let colors = new Set(['red', 'green', 'blue']);
2
3// Using forEach
4colors.forEach(color => {
5 console.log(color);
6});
7// Output:
8// red
9// green
10// blue
11
12// Using for...of loop
13for (let color of colors) {
14 console.log(color);
15}
16// Output:
17// red
18// green
19// blue
20
21// Converting Set to Array
22let colorsArray = [...colors]; // or Array.from(colors)
23console.log(colorsArray); // ["red", "green", "blue"]

Practical Use Cases for Sets

Removing Duplicates

JavaScript
// Remove duplicates from an array
let numbers = [1, 2, 3, 2, 1, 4, 5, 4];
let uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]

Tracking Unique Visitors

JavaScript
// Track unique user IDs
let visitors = new Set();
function trackVisitor(userId) {
visitors.add(userId);
return visitors.size; // Total unique visitors
}
console.log(trackVisitor("user1")); // 1
console.log(trackVisitor("user2")); // 2
console.log(trackVisitor("user1")); // 2 (still)

Set Operations (Union, Intersection, Difference)

JavaScript doesn't have built-in methods for set operations like union, intersection, and difference, but we can implement them easily:

JavaScript
1// Set operations
2let setA = new Set([1, 2, 3, 4]);
3let setB = new Set([3, 4, 5, 6]);
4
5// Union (A ∪ B): all elements from both sets
6let union = new Set([...setA, ...setB]);
7console.log([...union]); // [1, 2, 3, 4, 5, 6]
8
9// Intersection (A ∩ B): elements that exist in both sets
10let intersection = new Set([...setA].filter(x => setB.has(x)));
11console.log([...intersection]); // [3, 4]
12
13// Difference (A - B): elements in A that are not in B
14let difference = new Set([...setA].filter(x => !setB.has(x)));
15console.log([...difference]); // [1, 2]
16
17// Symmetric Difference (A △ B): elements in either set but not in both
18let symmetricDifference = new Set(
19 [...setA].filter(x => !setB.has(x)).concat([...setB].filter(x => !setA.has(x)))
20);
21console.log([...symmetricDifference]); // [1, 2, 5, 6]

JavaScript Maps

A Map is a collection of key-value pairs where keys can be of any data type. Unlike objects, Maps maintain the insertion order of elements and offer better performance for frequent additions and removals.

Creating a Map

JavaScript
1// Creating an empty Map
2let emptyMap = new Map();
3
4// Creating a Map with initial key-value pairs
5let userRoles = new Map([
6 ['john', 'admin'],
7 ['sarah', 'editor'],
8 ['mike', 'subscriber']
9]);
10
11console.log(userRoles); // Map(3) {"john" => "admin", "sarah" => "editor", "mike" => "subscriber"}

Basic Map Operations

JavaScript
1let userPreferences = new Map();
2
3// Adding key-value pairs
4userPreferences.set('theme', 'dark');
5userPreferences.set('fontSize', 16);
6userPreferences.set('notifications', true);
7
8console.log(userPreferences);
9// Map(3) {"theme" => "dark", "fontSize" => 16, "notifications" => true}
10
11// Getting values
12console.log(userPreferences.get('theme')); // "dark"
13console.log(userPreferences.get('fontSize')); // 16
14console.log(userPreferences.get('unknown')); // undefined
15
16// Checking if a key exists
17console.log(userPreferences.has('notifications')); // true
18console.log(userPreferences.has('language')); // false
19
20// Getting the size
21console.log(userPreferences.size); // 3
22
23// Deleting a key-value pair
24userPreferences.delete('notifications');
25console.log(userPreferences.has('notifications')); // false
26
27// Clearing all entries
28userPreferences.clear();
29console.log(userPreferences.size); // 0

Maps vs. Objects

While Maps and Objects are both collections of key-value pairs, they have important differences:

FeatureMapObject
Key TypesAny value (objects, functions, primitives)Only strings and symbols
SizeAvailable via size propertyManual calculation required
IterationDirectly iterable in insertion orderRequires extra steps, order not guaranteed
Default KeysNo default keysHas prototype keys that might conflict
PerformanceBetter for frequent additions/removalsBetter for simple scenarios
JSON SupportNo direct supportDirect support

Using Non-String Keys

One of the most powerful features of Maps is the ability to use any value as a key, including objects:

JavaScript
1// Using objects as keys
2let userObj1 = { id: 1, name: 'John' };
3let userObj2 = { id: 2, name: 'Sarah' };
4
5let userScores = new Map();
6userScores.set(userObj1, 85);
7userScores.set(userObj2, 92);
8
9console.log(userScores.get(userObj1)); // 85
10console.log(userScores.get(userObj2)); // 92
11
12// Using functions as keys
13function sayHello() { return 'Hello'; }
14function sayBye() { return 'Goodbye'; }
15
16let functionCalls = new Map();
17functionCalls.set(sayHello, 0);
18functionCalls.set(sayBye, 0);
19
20// Tracking function calls
21function trackCall(fn) {
22 let currentCount = functionCalls.get(fn);
23 functionCalls.set(fn, currentCount + 1);
24 return fn();
25}
26
27trackCall(sayHello); // "Hello"
28trackCall(sayHello); // "Hello"
29trackCall(sayBye); // "Goodbye"
30
31console.log(functionCalls.get(sayHello)); // 2
32console.log(functionCalls.get(sayBye)); // 1

Iterating Through a Map

JavaScript
1let fruitInventory = new Map([
2 ['apples', 50],
3 ['bananas', 30],
4 ['oranges', 25]
5]);
6
7// Iterating over key-value pairs
8for (let [fruit, count] of fruitInventory) {
9 console.log(`${fruit}: ${count}`);
10}
11// Output:
12// apples: 50
13// bananas: 30
14// oranges: 25
15
16// Using forEach
17fruitInventory.forEach((count, fruit) => {
18 console.log(`${fruit}: ${count}`);
19});
20// Output:
21// apples: 50
22// bananas: 30
23// oranges: 25
24
25// Getting all keys
26console.log([...fruitInventory.keys()]); // ["apples", "bananas", "oranges"]
27
28// Getting all values
29console.log([...fruitInventory.values()]); // [50, 30, 25]
30
31// Getting all entries
32console.log([...fruitInventory.entries()]); // [["apples", 50], ["bananas", 30], ["oranges", 25]]

Practical Use Cases for Maps

Cache with Object Keys

JavaScript
// Using Map as a cache with complex keys
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('Cache hit!');
return cache.get(key);
}
const result = fn(...args);
cache.set(key, result);
return result;
};
}
// Expensive calculation function
const calculateFactorial = memoize(n => {
console.log('Calculating factorial...');
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
});
console.log(calculateFactorial(5)); // Calculates
console.log(calculateFactorial(5)); // Uses cache

User Session Tracking

JavaScript
// Tracking user sessions
const userSessions = new Map();
function logUserActivity(userId, activity) {
// Get or create user's activity log
if (!userSessions.has(userId)) {
userSessions.set(userId, []);
}
// Add timestamp and activity
const activities = userSessions.get(userId);
activities.push({
timestamp: new Date(),
action: activity
});
return activities.length;
}
logUserActivity('user123', 'login');
logUserActivity('user123', 'view-profile');
logUserActivity('user456', 'login');
console.log(userSessions.get('user123'));

WeakMap and WeakSet

JavaScript also provides WeakMap and WeakSet, which are versions of Map and Set that don't prevent their keys (WeakMap) or values (WeakSet) from being garbage collected.

WeakMap

A WeakMap is similar to a Map, but:

  • Keys must be objects (not primitive values)
  • Keys are held "weakly", allowing them to be garbage collected if no other references exist
  • It's not iterable and doesn't have size property
  • Only has get, set, has, and delete methods
JavaScript
1// Creating a WeakMap
2let weakMap = new WeakMap();
3
4// Using objects as keys
5let obj1 = { name: 'Object 1' };
6let obj2 = { name: 'Object 2' };
7
8weakMap.set(obj1, 'Data for object 1');
9weakMap.set(obj2, 'Data for object 2');
10
11console.log(weakMap.get(obj1)); // "Data for object 1"
12
13// If we remove all other references to obj1
14obj1 = null;
15
16// The entry in weakMap will be automatically removed during garbage collection
17// (We can't demonstrate this directly in code as garbage collection timing is unpredictable)

WeakSet

A WeakSet is similar to a Set, but:

  • Values must be objects (not primitive values)
  • Values are held "weakly", allowing them to be garbage collected
  • It's not iterable and doesn't have size property
  • Only has add, has, and delete methods
JavaScript
1// Creating a WeakSet
2let weakSet = new WeakSet();
3
4// Using objects as values
5let obj1 = { name: 'Object 1' };
6let obj2 = { name: 'Object 2' };
7
8weakSet.add(obj1);
9weakSet.add(obj2);
10
11console.log(weakSet.has(obj1)); // true
12
13// If we remove all other references to obj1
14obj1 = null;
15
16// The value in weakSet will be automatically removed during garbage collection

Use Cases for WeakMap and WeakSet

These are specialized data structures with specific use cases:

JavaScript
1// Using WeakMap for private data
2const privateData = new WeakMap();
3
4class User {
5 constructor(name, age) {
6 this.name = name; // Public property
7
8 // Store "private" data in the WeakMap
9 privateData.set(this, { age: age });
10 }
11
12 getAge() {
13 return privateData.get(this).age;
14 }
15
16 setAge(age) {
17 privateData.get(this).age = age;
18 }
19}
20
21let user = new User('John', 30);
22console.log(user.name); // "John" (public)
23console.log(user.getAge()); // 30 (private)
24
25// When the user object is no longer referenced,
26// its private data will be garbage collected too

When to Use Weak Collections

Use WeakMap and WeakSet when:

  • You need to associate data with objects without preventing garbage collection
  • You want to store "private" data for objects
  • You need to cache results related to objects that might be removed
  • You want to avoid memory leaks in long-running applications

Choosing Between Arrays, Objects, Maps, and Sets

Use CaseBest ChoiceWhy
Simple ordered collection of itemsArrayStraightforward, indexed access
Collection of unique valuesSetAutomatically handles uniqueness
Simple key-value pairs with string keysObjectLightweight, JSON compatible
Key-value pairs with non-string keysMapSupports any key type
Frequent additions/removalsMap/SetBetter performance for these operations
Need to serialize/deserializeArray/ObjectDirect JSON support

Practice Exercises

Try these exercises to reinforce your understanding of Maps and Sets:

JavaScript
// 1. Create a function that counts the frequency of each word in a string
// using a Map. Return the Map sorted by frequency (most frequent first).
// 2. Create a function that takes two arrays and returns an array containing
// only the elements that appear in both arrays (using Set).
// 3. Implement a simple cache system using WeakMap that stores calculation
// results for object inputs, but allows objects to be garbage collected
// when they're no longer used elsewhere.
// 4. Create a function that groups an array of objects by a specified property
// using a Map (similar to SQL GROUP BY).
// 5. Implement a "unique by property" function that removes objects from an
// array if another object has the same value for a specified property.

Summary

In this tutorial, you've learned:

  • How to create and use Sets for collections of unique values
  • How to create and use Maps for flexible key-value pairs
  • The differences between Maps and Objects
  • How to perform set operations like union and intersection
  • How to iterate through Maps and Sets
  • When to use WeakMap and WeakSet for memory-sensitive applications
  • How to choose the right collection type for different scenarios

Maps and Sets are powerful additions to JavaScript's collection types. While arrays and objects are still the workhorses of JavaScript data structures, Maps and Sets provide specialized functionality that can make your code more efficient and expressive in certain scenarios.

Related Tutorials

Learn about arrays and how to work with collections of data.

Learn more

Learn about objects and how to work with key-value pairs.

Learn more

Learn how to interact with web page elements using JavaScript.

Learn more