Skip to main content

Command Palette

Search for a command to run...

Map and Set in JavaScript: When and Why to Use Them

Published
18 min read

Introduction

For years, JavaScript developers relied on objects for storing key-value pairs and arrays for storing collections of values. While these work well for many situations, they have limitations. JavaScript introduced Map and Set to provide better solutions for specific use cases. Maps are perfect for storing key-value pairs where keys can be any type, and Sets are ideal for storing unique values. In this blog, we'll explore Map and Set in detail, understand their advantages over traditional objects and arrays, and learn when to use each one.


1. What is Map?

A Map is a collection of key-value pairs where both keys and values can be of any data type. It's similar to an object, but more flexible and with better performance for certain operations.

Basic Concept:

// Creating an empty Map
const emptyMap = new Map();

// Creating a Map with initial values
const userMap = new Map([
  ["user1", "Ashish"],
  ["user2", "Priya"],
  ["user3", "Anil"]
]);

console.log(userMap);
// Map(3) {
//   'user1' => 'Ashish',
//   'user2' => 'Priya',
//   'user3' => 'Anil'
// }

Notice the => arrow symbol. This is how Maps display key-value pairs.

Adding Items to a Map:

const productMap = new Map();

// Use .set() to add key-value pairs
productMap.set("laptop", 50000);
productMap.set("phone", 30000);
productMap.set("tablet", 20000);

console.log(productMap);
// Map(3) {
//   'laptop' => 50000,
//   'phone' => 30000,
//   'tablet' => 20000
// }

Accessing Values:

const priceMap = new Map([
  ["apple", 100],
  ["banana", 50],
  ["orange", 80]
]);

// Use .get() to retrieve values
console.log(priceMap.get("apple")); // 100
console.log(priceMap.get("banana")); // 50
console.log(priceMap.get("orange")); // 80

// If key doesn't exist, returns undefined
console.log(priceMap.get("mango")); // undefined

Checking if Key Exists:

const userMap = new Map([
  ["user1", "Raj"],
  ["user2", "Priya"]
]);

// Use .has() to check if key exists
console.log(userMap.has("user1")); // true
console.log(userMap.has("user3")); // false

if (userMap.has("user1")) {
  console.log(userMap.get("user1")); // Raj
}

Deleting and Clearing:

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

// Remove a specific key
map.delete("b");
console.log(map.size); // 2

// Clear entire map
map.clear();
console.log(map.size); // 0

Getting Map Size:

const map = new Map();
console.log(map.size); // 0

map.set("key1", "value1");
console.log(map.size); // 1

map.set("key2", "value2");
console.log(map.size); // 2

Key Property: Keys Can Be Any Type

This is a huge advantage of Maps over objects!

const map = new Map();

// String key
map.set("name", "Vikram");

// Number key
map.set(1, "One");

// Boolean key
map.set(true, "Yes");

// Object as key
const userObj = { id: 1 };
map.set(userObj, "User object as key");

// Function as key
function myFunc() {}
map.set(myFunc, "Function as key");

console.log(map.get("name")); // "Vikram"
console.log(map.get(1)); // "One"
console.log(map.get(true)); // "Yes"
console.log(map.get(userObj)); // "User object as key"
console.log(map.get(myFunc)); // "Function as key"

With objects, all keys are converted to strings. With Map, keys stay as their original type.

Iterating Over a Map:

const scoreMap = new Map([
  ["Raj", 85],
  ["Priya", 92],
  ["Anil", 78]
]);

// Method 1: Using forEach
scoreMap.forEach((value, key) => {
  console.log(`\({key}: \){value}`);
});
// Output:
// Raj: 85
// Priya: 92
// Anil: 78

// Method 2: Using for...of with entries()
for (const [key, value] of scoreMap.entries()) {
  console.log(`\({key}: \){value}`);
}

// Method 3: Get only keys
for (const key of scoreMap.keys()) {
  console.log(key);
}

// Method 4: Get only values
for (const value of scoreMap.values()) {
  console.log(value);
}

2. What is Set?

A Set is a collection of unique values. Any value in a Set appears only once, even if you try to add it multiple times.

Basic Concept:

// Creating an empty Set
const emptySet = new Set();

// Creating a Set with initial values
const numberSet = new Set([1, 2, 3, 4, 5]);

console.log(numberSet);
// Set(5) { 1, 2, 3, 4, 5 }

Adding Items to a Set:

const colorSet = new Set();

// Use .add() to add values
colorSet.add("Red");
colorSet.add("Green");
colorSet.add("Blue");

console.log(colorSet);
// Set(3) { 'Red', 'Green', 'Blue' }

// Try to add a duplicate
colorSet.add("Red"); // No error, but duplicate is ignored

console.log(colorSet);
// Set(3) { 'Red', 'Green', 'Blue' } - Still 3 items!

The key property of Set is uniqueness. Duplicates are automatically ignored.

Checking if Value Exists:

const fruits = new Set(["Apple", "Banana", "Orange"]);

// Use .has() to check if value exists
console.log(fruits.has("Apple")); // true
console.log(fruits.has("Mango")); // false

if (fruits.has("Apple")) {
  console.log("Apple is in the set");
}

Deleting and Clearing:

const set = new Set([1, 2, 3, 4, 5]);

// Remove a specific value
set.delete(3);
console.log(set.size); // 4

// Clear entire set
set.clear();
console.log(set.size); // 0

Getting Set Size:

const set = new Set();
console.log(set.size); // 0

set.add("item1");
console.log(set.size); // 1

set.add("item2");
set.add("item3");
console.log(set.size); // 3

Set Can Store Any Type:

const mixedSet = new Set();

// String
mixedSet.add("text");

// Number
mixedSet.add(42);

// Boolean
mixedSet.add(true);

// Object
mixedSet.add({ name: "Raj" });

// Array
mixedSet.add([1, 2, 3]);

// Function
mixedSet.add(function() {});

console.log(mixedSet.size); // 6

Iterating Over a Set:

const languageSet = new Set(["JavaScript", "Python", "Java", "Go"]);

// Method 1: Using forEach
languageSet.forEach(value => {
  console.log(value);
});
// Output:
// JavaScript
// Python
// Java
// Go

// Method 2: Using for...of
for (const value of languageSet) {
  console.log(value);
}

// Method 3: Convert to Array
const languageArray = Array.from(languageSet);
console.log(languageArray);

Practical Use: Removing Duplicates

// Array with duplicates
const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5];

// Convert to Set (duplicates removed)
const uniqueNumbers = new Set(numbers);

// Convert back to Array if needed
const uniqueArray = Array.from(uniqueNumbers);

console.log(uniqueArray); // [1, 2, 3, 4, 5]

3. Difference Between Map and Object

While both store key-value pairs, Map and Object have important differences.

Difference 1: Key Types

// OBJECT: Keys are always converted to strings
const obj = {};
obj[1] = "one";
obj[true] = "yes";
obj[{ id: 1 }] = "object";

console.log(Object.keys(obj)); // ["1", "true", "[object Object]"]
// All keys are strings!

// MAP: Keys keep their original type
const map = new Map();
map.set(1, "one");
map.set(true, "yes");
map.set({ id: 1 }, "object");

console.log(map.size); // 3
console.log(map.get(1)); // "one"
console.log(map.get(true)); // "yes"

Difference 2: Method Availability

// OBJECT: Limited methods
const obj = { name: "Raj", age: 25 };
console.log(obj.name); // Raj
console.log(Object.keys(obj)); // ["name", "age"]
console.log(obj.hasOwnProperty("name")); // true
delete obj.age; // Delete property

// MAP: Better methods for key-value operations
const map = new Map([["name", "Raj"], ["age", 25]]);
console.log(map.get("name")); // Raj
console.log(map.has("name")); // true
map.delete("age"); // Delete entry
map.clear(); // Clear all entries

Difference 3: Size Property

// OBJECT: No built-in size
const obj = { a: 1, b: 2, c: 3 };
console.log(obj.size); // undefined
// Have to use Object.keys(obj).length
console.log(Object.keys(obj).length); // 3

// MAP: Built-in size property
const map = new Map([["a", 1], ["b", 2], ["c", 3]]);
console.log(map.size); // 3 - Much easier!

Difference 4: Iteration

// OBJECT: Not directly iterable
const obj = { name: "Priya", city: "Delhi" };
// for (const value of obj) { } // ERROR!

// Have to convert to array first
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

// MAP: Directly iterable
const map = new Map([["name", "Priya"], ["city", "Delhi"]]);
// Works directly!
for (const [key, value] of map) {
  console.log(key, value);
}

Difference 5: Performance

// MAP is generally faster for frequent add/delete operations
const map = new Map();

// Adding and deleting is optimized
map.set("key1", "value1");
map.delete("key1");
map.set("key2", "value2");

// OBJECT operations can be slower with many properties
const obj = {};
obj.key1 = "value1";
delete obj.key1;
obj.key2 = "value2";

Comparison Table:

Feature Object Map
Key Types Strings only Any type
Size .length or Object.keys() .size property
Iteration Requires Object.entries() Direct iteration
Performance Good for small data Better for frequent changes
Methods Limited has(), get(), delete(), clear()
Inheritance Prototypes matter None

When to Use:

// Use OBJECT when:
// - Keys are strings
// - You want simple property access
// - You need prototype features

const user = {
  name: "Arun",
  email: "arun@example.com",
  age: 26
};

// Use MAP when:
// - Keys might not be strings
// - You need frequent add/delete
// - You need guaranteed size property

const urlCache = new Map();
urlCache.set(new URL("https://example.com"), "cached data");

4. Difference Between Set and Array

While both store collections of values, Set and Array have different characteristics.

Difference 1: Uniqueness

// ARRAY: Allows duplicates
const arr = [1, 2, 2, 3, 3, 3, 4];
console.log(arr.length); // 7 - Includes duplicates

// SET: Only unique values
const set = new Set([1, 2, 2, 3, 3, 3, 4]);
console.log(set.size); // 4 - Duplicates removed automatically

Difference 2: Methods Available

// ARRAY: Lots of array methods
const arr = [1, 2, 3, 4, 5];
arr.push(6); // Add
arr.pop(); // Remove last
arr.map(x => x * 2); // Transform
arr.filter(x => x > 2); // Filter
arr.find(x => x === 3); // Find
arr.indexOf(3); // Get index

// SET: Simpler, specific methods
const set = new Set([1, 2, 3, 4, 5]);
set.add(6); // Add
set.delete(5); // Delete specific value
set.has(3); // Check existence
set.clear(); // Clear all
// No filter, map, find, etc. built-in

Difference 3: Access Pattern

// ARRAY: Access by index
const arr = ["a", "b", "c", "d"];
console.log(arr[0]); // "a"
console.log(arr[2]); // "c"
console.log(arr.length); // 4

// SET: No index access
const set = new Set(["a", "b", "c", "d"]);
console.log(set[0]); // undefined - No index access!
console.log(set.size); // 4

// To get values, must iterate
for (const value of set) {
  console.log(value);
}

Difference 4: Order

// ARRAY: Maintains insertion order
const arr = [3, 1, 4, 1, 5, 9];
console.log(arr); // [3, 1, 4, 1, 5, 9] - Order preserved

// SET: Also maintains insertion order (in modern JS)
const set = new Set([3, 1, 4, 1, 5, 9]);
for (const value of set) {
  console.log(value); // 3, 1, 4, 5, 9 (order preserved, duplicates removed)
}

Difference 5: Performance for Contains Check

// ARRAY: O(n) complexity - must search through all items
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(arr.includes(5)); // true - Has to check each item

// SET: O(1) complexity - instant lookup
const set = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
console.log(set.has(5)); // true - Instant lookup

For large collections, Set is much faster for checking existence.

Comparison Table:

Feature Array Set
Duplicates Allows Rejects
Index Access Yes (arr[0]) No
Methods Many (map, filter, etc.) Few (add, delete, etc.)
Check Existence .includes() - slow .has() - fast
Size .length .size
Order Preserved Preserved

When to Use:

// Use ARRAY when:
// - Order matters
// - You need to transform values
// - You need index access
// - Duplicates are meaningful

const scores = [85, 92, 78, 95, 92]; // Score list where duplicates matter

const names = ["Raj", "Priya", "Anil"]; // Ordered list

// Use SET when:
// - You need unique values
// - You frequently check for existence
// - You don't need index access
// - Duplicates should be eliminated

const uniqueTags = new Set(["javascript", "react", "javascript"]);
console.log(uniqueTags.size); // 2 - Duplicates removed

const visitedUrls = new Set();
if (!visitedUrls.has(url)) {
  visitedUrls.add(url); // Fast lookup and addition
}

5. When to Use Map and Set

Understanding when to use Map and Set instead of objects and arrays is crucial for writing efficient code.

Use Map When:

1. Keys Are Not Strings

// BAD: Using object with non-string keys
const obj = {};
obj[1] = "one";
obj[2] = "two";
const key = 1;
console.log(obj[key]); // Works but key is converted to string

// GOOD: Using Map with non-string keys
const map = new Map();
map.set(1, "one");
map.set(2, "two");
const key = 1;
console.log(map.get(key)); // Perfect!

2. Frequent Add/Delete Operations

// Cache with frequent updates
const userCache = new Map();

function cacheUser(id, userData) {
  userCache.set(id, userData);
}

function getCachedUser(id) {
  return userCache.get(id);
}

function clearExpiredUser(id) {
  userCache.delete(id);
}

3. You Need a Built-in Size

// Tracking connected clients
const connectedClients = new Map();

function addClient(clientId, clientData) {
  connectedClients.set(clientId, clientData);
  console.log(`Connected clients: ${connectedClients.size}`);
}

4. Using Objects as Keys

// Map DOM elements to their data
const elementDataMap = new Map();

const button1 = document.querySelector("#btn1");
const button2 = document.querySelector("#btn2");

elementDataMap.set(button1, { clickCount: 0 });
elementDataMap.set(button2, { clickCount: 0 });

button1.addEventListener("click", () => {
  const data = elementDataMap.get(button1);
  data.clickCount++;
  console.log(`Clicked ${data.clickCount} times`);
});

Use Set When:

1. Removing Duplicates

// Get unique users from multiple lists
const group1Users = ["Raj", "Priya", "Anil"];
const group2Users = ["Priya", "Anil", "Vikram"];

const allUsers = new Set([...group1Users, ...group2Users]);
console.log(allUsers); // Set(4) { 'Raj', 'Priya', 'Anil', 'Vikram' }

2. Checking Membership Quickly

// Check if user has permission
const adminUsers = new Set(["user1", "user5", "user8"]);

function isAdmin(userId) {
  return adminUsers.has(userId); // O(1) lookup
}

console.log(isAdmin("user5")); // true
console.log(isAdmin("user3")); // false

3. Finding Unique Elements

// Find unique words in a text
const text = "javascript javascript is fun is fun";
const words = text.split(" ");
const uniqueWords = new Set(words);

console.log(uniqueWords); // Set(4) { 'javascript', 'is', 'fun' }
console.log(`Unique words: ${uniqueWords.size}`);

4. Tracking Visited/Processed Items

// Web crawler tracking visited URLs
const visitedUrls = new Set();

async function crawl(url) {
  if (visitedUrls.has(url)) {
    return; // Already visited
  }
  
  visitedUrls.add(url);
  console.log(`Crawling ${url}`);
  // Fetch and process...
}

5. Creating Filtered Lists

// Get common elements between two arrays
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];

const set1 = new Set(arr1);
const common = arr2.filter(item => set1.has(item));

console.log(common); // [3, 4, 5]

6. Real-World Examples

Example 1: User Authentication and Session Management (Map)

// Store user sessions
const activeSessions = new Map();

class SessionManager {
  createSession(userId, sessionToken) {
    const sessionData = {
      userId: userId,
      createdAt: new Date(),
      lastActivity: new Date()
    };
    activeSessions.set(sessionToken, sessionData);
    console.log(`Session created. Active sessions: ${activeSessions.size}`);
  }
  
  getSession(sessionToken) {
    return activeSessions.get(sessionToken);
  }
  
  isValidSession(sessionToken) {
    if (!activeSessions.has(sessionToken)) {
      return false;
    }
    
    const session = activeSessions.get(sessionToken);
    const now = new Date();
    const expireTime = 30 * 60 * 1000; // 30 minutes
    
    if (now - session.lastActivity > expireTime) {
      activeSessions.delete(sessionToken);
      return false;
    }
    
    session.lastActivity = now;
    return true;
  }
  
  endSession(sessionToken) {
    activeSessions.delete(sessionToken);
  }
  
  getActiveSessions() {
    return activeSessions.size;
  }
}

// Usage
const manager = new SessionManager();
manager.createSession("user1", "token_abc123");
manager.createSession("user2", "token_xyz789");
console.log("Active:", manager.getActiveSessions()); // 2
manager.endSession("token_abc123");
console.log("Active:", manager.getActiveSessions()); // 1

Example 2: Tracking Unique Visitors (Set)

// Track unique visitors to a website
const uniqueVisitors = new Set();
const visitorLog = [];

function recordVisit(userId) {
  // Add to unique visitors
  if (!uniqueVisitors.has(userId)) {
    uniqueVisitors.add(userId);
    console.log(`New visitor: ${userId}`);
  } else {
    console.log(`Returning visitor: ${userId}`);
  }
  
  // Log the visit
  visitorLog.push({
    userId: userId,
    timestamp: new Date()
  });
}

function getUniqueVisitorCount() {
  return uniqueVisitors.size;
}

// Usage
recordVisit("user1");
recordVisit("user2");
recordVisit("user1"); // Returning visitor
recordVisit("user3");
console.log(`Total unique visitors: ${getUniqueVisitorCount()}`); // 3

Example 3: Product Inventory with Tags (Map + Set)

// Store products with their tags (Set for unique tags)
const productInventory = new Map();

class Product {
  constructor(id, name, price) {
    this.id = id;
    this.name = name;
    this.price = price;
    this.tags = new Set();
  }
  
  addTag(tag) {
    this.tags.add(tag);
  }
  
  hasTag(tag) {
    return this.tags.has(tag);
  }
  
  getTags() {
    return Array.from(this.tags);
  }
}

// Add products
const laptop = new Product(1, "Laptop", 50000);
laptop.addTag("electronics");
laptop.addTag("computers");
laptop.addTag("expensive");

productInventory.set(1, laptop);

// Query products
function findProductsByTag(tag) {
  const results = [];
  for (const [id, product] of productInventory) {
    if (product.hasTag(tag)) {
      results.push(product);
    }
  }
  return results;
}

console.log(findProductsByTag("electronics")); // [Product...]
console.log(laptop.getTags()); // ["electronics", "computers", "expensive"]

Example 4: Finding Common and Unique Elements (Set)

// Comparing two lists
const team1 = new Set(["Raj", "Priya", "Anil", "Sneha"]);
const team2 = new Set(["Priya", "Anil", "Vikram", "Arjun"]);

// Common members
const commonMembers = new Set([...team1].filter(member => team2.has(member)));
console.log("Common:", commonMembers); // Set(2) { 'Priya', 'Anil' }

// Only in team1
const onlyTeam1 = new Set([...team1].filter(member => !team2.has(member)));
console.log("Only team1:", onlyTeam1); // Set(2) { 'Raj', 'Sneha' }

// Only in team2
const onlyTeam2 = new Set([...team2].filter(member => !team1.has(member)));
console.log("Only team2:", onlyTeam2); // Set(2) { 'Vikram', 'Arjun' }

// All members combined (union)
const allMembers = new Set([...team1, ...team2]);
console.log("All:", allMembers); // Set(6) { 'Raj', 'Priya', ... }

7. Map and Set Methods Reference

Map Methods:

const map = new Map();

// Add/Update
map.set(key, value);

// Retrieve
map.get(key);

// Check existence
map.has(key);

// Delete
map.delete(key);

// Clear all
map.clear();

// Size
map.size;

// Iterate
for (const [key, value] of map) { }
map.forEach((value, key) => { });
map.keys();
map.values();
map.entries();

Set Methods:

const set = new Set();

// Add
set.add(value);

// Check existence
set.has(value);

// Delete
set.delete(value);

// Clear all
set.clear();

// Size
set.size;

// Iterate
for (const value of set) { }
set.forEach((value) => { });
set.values();
set.keys(); // Same as values()
set.entries(); // Returns [value, value] pairs

8. Performance Comparison

// Check existence performance comparison

// With Array - O(n) complexity
const arr = Array.from({ length: 100000 }, (_, i) => i);
console.time("Array.includes");
arr.includes(99999); // Slow - must check each item
console.timeEnd("Array.includes"); // ~0.5ms+

// With Set - O(1) complexity
const set = new Set(arr);
console.time("Set.has");
set.has(99999); // Fast - instant lookup
console.timeEnd("Set.has"); // ~0.001ms

// For large datasets, Set is much faster for membership checks

9. Converting Between Structures

// Array to Set (remove duplicates)
const arr = [1, 2, 2, 3, 3, 3];
const set = new Set(arr);
console.log(set); // Set(3) { 1, 2, 3 }

// Set to Array
const set2 = new Set(["a", "b", "c"]);
const arr2 = Array.from(set2);
console.log(arr2); // ["a", "b", "c"]

// Or using spread
const arr3 = [...set2];
console.log(arr3); // ["a", "b", "c"]

// Object to Map
const obj = { name: "Raj", age: 25 };
const map = new Map(Object.entries(obj));
console.log(map.get("name")); // "Raj"

// Map to Object
const map2 = new Map([["x", 1], ["y", 2]]);
const obj2 = Object.fromEntries(map2);
console.log(obj2); // { x: 1, y: 2 }

10. Common Patterns

Pattern 1: Group By Using Map

const students = [
  { name: "Raj", grade: "A" },
  { name: "Priya", grade: "B" },
  { name: "Anil", grade: "A" },
  { name: "Sneha", grade: "C" }
];

// Group students by grade
const studentsByGrade = new Map();

students.forEach(student => {
  if (!studentsByGrade.has(student.grade)) {
    studentsByGrade.set(student.grade, []);
  }
  studentsByGrade.get(student.grade).push(student);
});

console.log(studentsByGrade.get("A")); // [Raj, Anil]
console.log(studentsByGrade.get("B")); // [Priya]

Pattern 2: Counter Using Map

const text = "hello world hello javascript";
const words = text.split(" ");

const wordCount = new Map();

words.forEach(word => {
  wordCount.set(word, (wordCount.get(word) || 0) + 1);
});

console.log(wordCount.get("hello")); // 2
console.log(wordCount.get("world")); // 1

Pattern 3: Cache Using Map

const cache = new Map();

function expensiveCalculation(n) {
  if (cache.has(n)) {
    console.log(`Returning cached result for ${n}`);
    return cache.get(n);
  }
  
  console.log(`Calculating result for ${n}`);
  const result = n * n * n; // Expensive calculation
  cache.set(n, result);
  return result;
}

console.log(expensiveCalculation(5)); // Calculating...
console.log(expensiveCalculation(5)); // Cached
console.log(expensiveCalculation(10)); // Calculating...

Conclusion

Map and Set are powerful data structures that solve specific problems better than objects and arrays:

Use Map When:

  • Keys might not be strings

  • You need frequent add/delete operations

  • You need a built-in size property

  • You want to use objects as keys

Use Set When:

  • You need unique values only

  • You need fast membership checking

  • You want to eliminate duplicates

  • You're tracking visited/processed items

Key Takeaways:

  1. Map stores key-value pairs with any key type

  2. Set stores unique values of any type

  3. Map has better performance for frequent updates

  4. Set has better performance for membership checks

  5. Both are more efficient than objects and arrays for their respective use cases

Master Map and Set, and you'll write more efficient, cleaner code. They're fundamental tools in modern JavaScript that every developer should be comfortable using.