ES6 - Collections
ES6+ - Modern Collections: Map, Set, WeakMap, WeakSet
Section titled “ES6+ - Modern Collections: Map, Set, WeakMap, WeakSet”ES6 introduced powerful new built-in data structures: Map, Set, WeakMap, and WeakSet. These provide more versatile ways to organize and manage collections of data compared to traditional objects and arrays.
The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value. This is a significant advantage over plain objects, where keys are implicitly converted to strings.
Syntax: `new Map([iterable])`Where `iterable` is an Array or other iterable object whose elements are key-value pairs (2-element Arrays like `[key, value]`).Key Map Properties and Methods:
Section titled “Key Map Properties and Methods:”map.size: Returns the number of key/value pairs in theMap.map.set(key, value): Adds or updates an element with a specified key and value. Returns theMapobject, allowing chaining.map.get(key): Returns the value associated with the key, orundefinedif the key can’t be found.map.has(key): Returns a boolean indicating whether an element with the specified key exists.map.delete(key): Removes the element with the specified key. Returnstrueif an element existed and was removed, otherwisefalse.map.clear(): Removes all key/value pairs from theMapobject.
Iteration Methods (all return Iterators):
Section titled “Iteration Methods (all return Iterators):”map.keys(): Returns a new Iterator object that contains the keys for each element in theMapin insertion order.map.values(): Returns a new Iterator object that contains the values for each element in theMapin insertion order.map.entries(): Returns a new Iterator object that contains an array of[key, value]for each element in theMapin insertion order. This is the default iterator for Maps.
map.forEach(callbackFn[, thisArg]): Executes callbackFn once for each key-value pair in the Map, in insertion order.
Example: Basic Map Operations
Section titled “Example: Basic Map Operations”const userRoles = new Map();
// Set key-value pairsuserRoles.set('admin', 'Administrator Access');userRoles.set('editor', 'Content Editor Access');userRoles.set(123, 'Numeric Key Example'); // Keys can be non-strings
const user = { id: 1 };userRoles.set(user, 'Object Key Example'); // Keys can be objects
console.log(userRoles.get('admin')); // Output: Administrator Accessconsole.log(userRoles.get(user)); // Output: Object Key Exampleconsole.log(userRoles.has('guest')); // Output: falseconsole.log(userRoles.size); // Output: 4
// Initialize with an array of key-value pairsconst settings = new Map([ ['theme', 'dark'], ['fontSize', 16]]);console.log(settings.get('theme')); // Output: dark
// Iterating over a Map using for...of (default is entries)for (const [key, value] of userRoles) { console.log(`${typeof key} ${key}: ${value}`);}// Example output for one entry: string admin: Administrator Access
// Iterating using forEachsettings.forEach((value, key) => { console.log(`Setting - ${key}: ${value}`);});// Output:// Setting - theme: dark// Setting - fontSize: 16WeakMap
Section titled “WeakMap”A WeakMap is a collection of key/value pairs where the keys must be objects and the values can be arbitrary. The references to the keys are held “weakly,” meaning that if there are no other references to a key object, that object can be garbage collected, and its corresponding entry in the WeakMap will be removed automatically. This makes WeakMaps useful for associating data with objects without preventing those objects from being garbage collected.
Key characteristics of WeakMap:
- Keys must be objects. Primitive values are not allowed as keys.
- Entries are not enumerable. You cannot iterate over a
WeakMap(nokeys(),values(),entries(),forEach(), orsizeproperty). - Only
get(key),set(key, value),has(key), anddelete(key)methods are available.
Example: Using a WeakMap
Section titled “Example: Using a WeakMap”let activeUsers = new WeakMap();
let user1 = { name: 'Alice' };let user2 = { name: 'Bob' };
activeUsers.set(user1, { lastLogin: Date.now() });activeUsers.set(user2, { status: 'online' });
console.log(activeUsers.has(user1)); // Output: trueconsole.log(activeUsers.get(user1)); // Output: { lastLogin: ... }
// If user1 becomes eligible for garbage collection (e.g., user1 = null and no other references exist),// its entry in activeUsers will eventually be removed by the garbage collector.user1 = null;// At some point, activeUsers.has(the_original_user1_object) would be false.The Set object lets you store unique values of any type, whether primitive values or object references. Values in a Set are ordered by insertion.
Syntax: `new Set([iterable])`Where `iterable` is an Array or other iterable object whose elements are used to initialize the set.Key Set Properties and Methods:
Section titled “Key Set Properties and Methods:”set.size: Returns the number of unique values in theSet.set.add(value): Appendsvalueto theSet. Returns theSetobject (chainable). Ifvaluealready exists, nothing changes.set.has(value): Returns a boolean indicating whether an element with the specified value exists.set.delete(value): Removes the specified value from theSet. Returnstrueif value was found and removed, otherwisefalse.set.clear(): Removes all elements from theSetobject.
Iteration Methods (all return Iterators):
Section titled “Iteration Methods (all return Iterators):”set.values(): Returns a new Iterator object that contains the values for each element in theSetin insertion order. This is the default iterator.set.keys(): An alias forvalues(), behaving identically.set.entries(): Returns a new Iterator object that contains an array of[value, value]for each element in theSet(to maintain consistency withMap).
set.forEach(callbackFn[, thisArg]): Executes callbackFn once for each value in the Set, in insertion order. The callback receives (value, key, set) where key is the same as value.
Example: Basic Set Operations
Section titled “Example: Basic Set Operations”const uniqueNumbers = new Set([1, 2, 2, 3, 4, 4, 4]);
console.log(uniqueNumbers.size); // Output: 4 (duplicates are ignored)
uniqueNumbers.add(5);uniqueNumbers.add(1); // Already exists, no changeconsole.log(uniqueNumbers.has(3)); // Output: true
uniqueNumbers.delete(2);console.log(uniqueNumbers.has(2)); // Output: false
// Iterating over a Set using for...of (default is values)for (const number of uniqueNumbers) { console.log(number);}// Output (in insertion order, e.g.): 1, 3, 4, 5
// Iterating using forEachuniqueNumbers.forEach(value => { console.log(`Set value: ${value}`);});WeakSet
Section titled “WeakSet”A WeakSet is a collection of objects only. Similar to WeakMap, references to objects in a WeakSet are held “weakly.” If an object in a WeakSet has no other references, it can be garbage collected.
Key characteristics of WeakSet:
- Can only store objects. Primitive values are not allowed.
- Entries are not enumerable. You cannot iterate over a
WeakSet(no iterators,forEach, orsize). - Only
add(value),has(value), anddelete(value)methods are available.
Example: Using a WeakSet
Section titled “Example: Using a WeakSet”let processedObjects = new WeakSet();
let obj1 = { id: 'A' };let obj2 = { id: 'B' };
function processObject(obj) { if (!processedObjects.has(obj)) { console.log(`Processing object: ${obj.id}`); // ... perform processing ... processedObjects.add(obj); } else { console.log(`Object ${obj.id} already processed.`); }}
processObject(obj1);processObject(obj2);processObject(obj1); // Will indicate it's already processed
// If obj1 becomes eligible for GC, its entry in processedObjects is removed.obj1 = null;Iterators in Collections
Section titled “Iterators in Collections”All standard collections (Array, Map, Set, String) in ES6+ are iterable. This means they implement the iterator protocol. An iterator is an object that knows how to access items from a collection one at a time, while keeping track of its current position within that sequence. Iterators have a next() method which returns an object with two properties: value (the next item in the sequence) and done (a boolean that is true if the iterator has reached the end of the sequence).
Example: Manual Iteration
Section titled “Example: Manual Iteration”const myMap = new Map([['a', 1], ['b', 2]]);const mapIterator = myMap.entries(); // Get an iterator
console.log(mapIterator.next()); // { value: ['a', 1], done: false }console.log(mapIterator.next()); // { value: ['b', 2], done: false }console.log(mapIterator.next()); // { value: undefined, done: true }
const mySet = new Set(['apple', 'banana']);const setIterator = mySet.values();
console.log(setIterator.next()); // { value: 'apple', done: false }console.log(setIterator.next()); // { value: 'banana', done: false }console.log(setIterator.next()); // { value: undefined, done: true }While manual iteration is possible, the for...of loop is the most common and convenient way to work with iterables.