Explain Set and Map.
JavaScript ES6 introduced two new built-in object types: `Set` and `Map`. These data structures provide efficient ways to store and manage collections of data, offering distinct advantages over traditional arrays and plain objects for specific use cases. They are iterable and preserve the order of insertion.
JavaScript Set
A Set is a collection of unique values. It's similar to an array but with the fundamental difference that duplicate values are automatically removed. This makes Set ideal for scenarios where you need to ensure that each item in your collection is distinct.
Key characteristics of a Set:
- Stores unique values: If you try to add an existing value, it will be ignored.
- Can store any data type: Numbers, strings, objects,
null,undefined, etc. - Order of insertion is preserved: Elements are iterated in the order they were added.
- No indexed access: You cannot access elements by an index like
mySet[0].
Common use cases for Set include removing duplicate items from an array, checking for the presence of an item, and managing a list of flags or unique identifiers.
Set Constructor and Methods
A Set can be created using the new Set() constructor, optionally passing an iterable (like an array) to initialize it.
const mySet = new Set();
const initialSet = new Set([1, 2, 2, 3, 4]); // Set will be {1, 2, 3, 4}
Key methods and properties:
add(value): Adds a new element to the Set. Returns the Set object.delete(value): Removes an element from the Set. Returnstrueif the element was present and removed,falseotherwise.has(value): Returnstrueif the value is in the Set,falseotherwise.clear(): Removes all elements from the Set.size: A property that returns the number of elements in the Set.forEach(callbackFn, thisArg?): Executes a provided function once for each Set value.values(),keys(),entries(): All return a new Iterator object that contains the values for each element in the Set in insertion order. (For Set,keys()andvalues()are the same).
const numbers = new Set();
numbers.add(10);
numbers.add(20);
numbers.add(10); // Ignored, 10 is already present
numbers.add(30);
console.log(numbers.size); // Output: 3
console.log(numbers.has(20)); // Output: true
numbers.delete(10);
console.log(numbers.has(10)); // Output: false
for (const num of numbers) {
console.log(num); // Output: 20, 30
}
JavaScript 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 a plain JavaScript object, but with some significant improvements, especially regarding keys.
Key characteristics of a Map:
- Keys can be any data type: Unlike objects, where keys are coerced to strings, Map allows keys to be numbers, booleans, objects, or even other Maps.
- Order of insertion is preserved: Elements are iterated in the order they were added.
- Better performance for frequent additions/removals: Maps are generally optimized for these operations.
- Iterability: Maps are directly iterable, making it easy to loop over their elements.
Maps are particularly useful when you need to store arbitrary mappings between two pieces of data, especially when your keys are not simple strings or symbols, or when you need to maintain insertion order.
Map Constructor and Methods
A Map can be created using the new Map() constructor, optionally passing an array of [key, value] pairs to initialize it.
const myMap = new Map();
const initialMap = new Map([
['name', 'Alice'],
[1, 'one'],
[true, 'yes']
]);
Key methods and properties:
set(key, value): Adds or updates a key-value pair in the Map. Returns the Map object.get(key): Returns the value associated with the specified key, orundefinedif the key is not found.delete(key): Removes a key-value pair from the Map. Returnstrueif an element was present and removed,falseotherwise.has(key): Returnstrueif the key exists in the Map,falseotherwise.clear(): Removes all key-value pairs from the Map.size: A property that returns the number of key-value pairs in the Map.forEach(callbackFn, thisArg?): Executes a provided function once for each key-value pair.keys(): Returns a new Iterator object that contains the keys for each element in the Map.values(): Returns a new Iterator object that contains the values for each element in the Map.entries(): Returns a new Iterator object that contains an array of[key, value]for each element in the Map.
const userRoles = new Map();
const user1 = { id: 1, name: 'Alice' };
const user2 = { id: 2, name: 'Bob' };
userRoles.set(user1, 'Admin');
userRoles.set(user2, 'Editor');
userRoles.set('guest', 'Viewer');
console.log(userRoles.get(user1)); // Output: Admin
console.log(userRoles.has('guest')); // Output: true
console.log(userRoles.size); // Output: 3
for (const [key, value] of userRoles) {
console.log(`${typeof key === 'object' ? key.name || 'Object' : key}: ${value}`);
// Output: Alice: Admin, Bob: Editor, guest: Viewer
}
Key Differences and When to Use Which
| Feature | Set | Map |
|---|---|---|
| Purpose | Stores unique values | Stores key-value pairs |
| Duplicates | Not allowed for values | Allowed for values; keys must be unique |
| Keys | Values are the 'keys' (no separate key concept) | Keys can be any data type (objects, primitives) |
| Values | Stores values directly | Stores values associated with keys |
| Access | Check for presence (`has()`) | Get value by key (`get(key)`) |
| Analogy | A list of unique items | A dictionary or object with flexible keys |
Choose a Set when you need a collection of unique items and your primary operations are adding items, removing items, and checking for the presence of an item. For example, tracking unique visitors, or keeping a list of tags without duplicates.
Choose a Map when you need to store associations between distinct pieces of data, especially if your keys are not simple strings or if you need to maintain the insertion order. For example, storing configuration data where keys might be objects, caching results based on complex inputs, or mapping IDs to complex user objects.
Conclusion
Set and Map are powerful additions to JavaScript's data structures, offering more specialized and often more efficient alternatives to arrays and plain objects for specific tasks. Understanding their strengths and use cases is crucial for writing clean, performant, and maintainable modern JavaScript code.