Maps and Sets in JavaScript
1. Use maps
In programming, maps are a type of data structure in which key-value pairs can be stored. This means that individual values can be stored for keys within a map, which can then be retrieved via the keys. The keys within a map must be unique, but values can occur more than once.
Maps are represented by the type Map, so instances can be created using the corresponding constructor function. An array of arrays is passed as a parameter. The arrays each contain the key as the first element and the value as the second element.
Complete Code - Examples/Part_196/main.js...
const cityPopulation = new Map( // Create a map ...
[ // ... on the basis of an array
['Tokyo', 37000000],
['Delhi', 32000000],
['Cairo', 22000000],
['New York', 8000000],
['Berlin', 4000000]
]
);
console.log(cityPopulation.size); // output: 5
Key | Value |
---|---|
Tokyo | 37.000.000 |
Delhi | 32.000.000 |
Cairo | 22.000.000 |
New York | 8.000.000 |
Berlin | 4.000.000 |
The constructor function of Map does not necessarily expect an array, but an object that can be iterated. An iterable object is an object that defines its own iteration behaviour so that it can be used directly as input in a loop, for example.
1.1. Basic operations
Here is a list of the methods that are possible with maps:
Method | Explanation |
---|---|
clear() | Deletes all key-value pairs from the map. |
delete() | Deletes the value of a transferred key from the map. If the deletion is successful, the method returns true, otherwise false. |
get() | Returns the associated value for a key. If the key does not exist in the map, the method returns an undefined. |
has() | Checks whether there is a value for a key in the map. If yes, the method returns true, otherwise false. |
set() | Sets the corresponding value for a key. If the key already exists in the map, the value associated with it is overwritten. |
size | Contains the number of key-value pairs in the map. |
entries() | Returns an iterator that can be used to iterate over the key-value pairs of the map |
keys() | Analogue to entries(), this method returns an iterator for the keys of the map. |
values() | Analogue to entries(), the method returns an iterator for the values of the map. |
The use of Map:
Complete Code - Examples/Part_197/main.js...
const cityPopulation = new Map(); // Create the map
cityPopulation.set('Tokyo', 37000000); // Add multiple entries
cityPopulation.set('Delhi', 32000000);
cityPopulation.set('Cairo', 22000000);
cityPopulation.set('New York', 8000000);
cityPopulation.set('Berlin', 4000000);
console.log(cityPopulation.get('Tokyo')); // output: 37000000
console.log(cityPopulation.size); // output: 5
console.log(cityPopulation.has('Tokyo')); // output: true
cityPopulation.delete('Tokyo'); // Delete an entry
console.log(cityPopulation.has('Tokyo')); // output: false
console.log(
cityPopulation.has('Shanghai') // output: false
);
cityPopulation.clear(); // Delete all entries
console.log(cityPopulation.size); // output: 0
The method calls of set() can be conveniently chained, as the method always returns the map as a return value and you can therefore call set() again directly:
Complete Code - Examples/Part_198/main.js...
const cityPopulation = new Map() // Create a map ...
.set('Tokyo', 37000000) // ... with method chaining
.set('Delhi', 32000000)
.set('Cairo', 22000000)
.set('New York', 8000000)
.set('Berlin', 4000000);
console.log(cityPopulation.size); // output: 5
1.2. Iterate over maps
The methods keys(), values() and entries() return so-called iterators, which can be used to iterate over the individual entries of the map:
Iterate over the keys of a map
Complete Code - Examples/Part_199/main.js...
const cityPopulation = new Map( // Create a map ...
[ // ... on the basis of an array
['Tokyo', 37000000],
['Delhi', 32000000],
['Cairo', 22000000],
['New York', 8000000],
['Berlin', 4000000]
]
);
for (const city of cityPopulation.keys()) {
console.log(city);
}
Here, the keys() method and the for-of loop are used to iterate over the keys of the cityPopulation map. The programme then returns the output Tokyo, Delhi, Cairo, New York, Berlin.
for-of vs for-in loop
The for-of loop differs from the for-in loop in that it does not iterate over the names of the object properties, but over the values associated with these properties.
Complete Code - Examples/Part_200/main.js...
const numbers = [ 7, 10, 18, 26, 42 ];
numbers.name = "Array of numbers";
// for-in-Loop
for (let i in numbers) {
console.log(i); // 0, 1, 2, 3, 4, name
}
// for-of-Loop
for (let i of numbers) {
console.log(i); // 7, 10, 18, 26, 42
}
The for-in loop outputs indices, which represent the properties for arrays, as well as the manually added name property, whereas the for-of loop outputs the values stored in the array.
Iterate over the values of a map
Here, the values() method is used to iterate over the values contained in the map:
Complete Code - Examples/Part_201/main.js...
const cityPopulation = new Map(); // Create the map
cityPopulation.set('Tokyo', 37000000); // Add multiple entries
cityPopulation.set('Delhi', 32000000);
cityPopulation.set('Cairo', 22000000);
cityPopulation.set('New York', 8000000);
cityPopulation.set('Berlin', 4000000);
for (let population of cityPopulation.values()) {
console.log(population);
}
/* output:
37000000
32000000
22000000
8000000
4000000
*/
Iterate over the key-value pairs of a map
If you want to iterate over the keys and values, use the entries() method. The corresponding iterator returned by this method returns an array with two entries in each iteration: the key in the first position and the stored value in the second position.
Complete Code - Examples/Part_202/main.js...
const cityPopulation = new Map(); // Create the map
cityPopulation.set('Tokyo', 37000000); // Add multiple entries
cityPopulation.set('Delhi', 32000000);
cityPopulation.set('Cairo', 22000000);
cityPopulation.set('New York', 8000000);
cityPopulation.set('Berlin', 4000000);
for (let entry of cityPopulation.entries()) {
console.log(entry[0]); // Key
console.log(entry[1]); // Value
}
// Alternatively, access via array destructuring:
for (let [ city, population ] of cityPopulation.entries()) {
console.log(city);
console.log(population);
}
/* output:
Tokyo
37000000
Delhi
32000000
Cairo
22000000
New York
8000000
Berlin
4000000
...
*/
Since the iterator returned by entries() is also the iterator that is stored in the Map object by default, you can also use the map directly as input for the for-of loop in this case:
Complete Code - Examples/Part_203/main.js...
const cityPopulation = new Map(); // Create the map
cityPopulation.set('Tokyo', 37000000); // Add multiple entries
cityPopulation.set('Delhi', 32000000);
cityPopulation.set('Cairo', 22000000);
cityPopulation.set('New York', 8000000);
cityPopulation.set('Berlin', 4000000);
for (let entry of cityPopulation) {
console.log(entry[0]); // Key
console.log(entry[1]); // Value
}
// Alternatively, access via array destructuring:
for (let [ city, population ] of cityPopulation) {
console.log(city);
console.log(population);
}
/* output:
Tokyo
37000000
Delhi
32000000
Cairo
22000000
New York
8000000
Berlin
4000000
...
*/
1.3. Use Weak Maps
In addition to the Map data type, the ECMAScript standard also provides the WeakMap data type. Weak maps are similar to normal maps, but they differ in one important respect: objects that are used as keys can be deleted as part of the garbage collection if these objects are no longer referenced. The objects in a weak map are therefore weakly referenced.
Garbage collection
In software development, this term refers to a mechanism that ensures that memory areas that are no longer required are regularly released during the runtime of a program in order to minimise the memory requirements of the program.
Weak maps have a direct impact on the API: Firstly, only objects can be used as keys and not primitive data types, as is the case with normal maps. This means that character strings are not permitted as keys in a weak map.
Secondly, the methods keys(), values() and entries() are not available for weak maps, as these methods would return iterators for which there is no guarantee that the internal state is still correct after a garbage collection. The size property is not available for a similar reason.
An example of the use of Weak Maps:
Complete Code - Examples/Part_204/main.js...
const city1 = {
name: 'Tokyo'
};
const city2 = {
name: 'Delhi'
};
const city3 = {
name: 'Cairo'
};
const city4 = {
name: 'New York'
};
const city5 = {
name: 'Berlin'
};
const city6 = {
name: 'Paris'
};
const cityPopulation = new WeakMap(); // Create the map
cityPopulation.set(city1, 37000000); // Add multiple entries
cityPopulation.set(city2, 32000000);
cityPopulation.set(city3, 22000000);
cityPopulation.set(city4, 8000000);
cityPopulation.set(city5, 4000000);
console.log(cityPopulation.get(city1)); // output: 37000000
console.log(cityPopulation.has(city1)); // output: true
cityPopulation.delete(city1); // Delete an entry
console.log(cityPopulation.has(city1)); // output: false
console.log(
cityPopulation.has(city6) // output: false
);
console.log(cityPopulation);
The keys used here are no longer strings but objects.
2. Use sets
In programming, a set is a data structure that is similar to a list, but in which the values may only occur once, i.e. duplicate values are not permitted. Sets have been available since ES2015 and are represented by the Set object. Whether two values are the same is checked for strict equality, i.e. both the value and type of a variable are taken into account.
The constructor function Set is used to create a set. As with maps, an array containing the initial values to be added to the set can be passed as the value:
Complete Code - Examples/Part_205/main.js...
const cities = new Set( // Create a set ...
[ // ... on the basis of an array
'Tokyo',
'Tokyo',
'Delhi',
'Cairo',
'New York',
'Berlin'
]
);
console.log(cities.size); // output: 5
A set was created here that contains five character strings as values. The duplicate character string Tokyo is only added to the set once, so that the set then has the size 5.
2.1. Basic operations
Here is a list of the methods that are possible with sets:
Method | Explanation |
---|---|
add() | Adds an element to the set. |
clear() | Deletes all elements from the set. |
delete() | Deletes the transferred element from the set. |
has() | Checks whether the transferred element is contained in the set. |
entries() | Returns an iterator containing the value-value pairs of the set. The order of the pairs corresponds to the order in which they were added to the set. |
keys() | Returns an iterator containing the values of the set. The order of the values corresponds to the order in which they were added to the set. |
values() | Like keys(), returns an iterator containing the values of the set. The order of the values corresponds to the order in which they were added to the set. |
size | Property that represents the number of elements in the set. |
The use of Set:
Complete Code - Examples/Part_206/main.js...
const cities = new Set(); // Create the set
cities.add('Tokyo'); // Add different values
cities.add('Tokyo');
cities.add('Delhi');
cities.add('Cairo');
cities.add('New York');
cities.add('Berlin');
console.log(cities.size); // output: 5
console.log(cities.has('Tokyo')); // output: true
cities.delete('Tokyo'); // Delete a value
console.log(cities.has('Tokyo')); // output: false
console.log(
cities.has('Paris') // output: false
);
cities.clear(); // Delete all values
console.log(cities.size); // output: 0
It is also possible to chain the calls of the sset() method:
Complete Code - Examples/Part_207/main.js...
const cities = new Set() // Create the set
.add('Tokyo') // ... with concatenation
.add('Delhi')
.add('Cairo')
.add('New York')
.add('Berlin');
console.log(cities.size); // output: 5
2.2. Iterate over sets
To iterate over the entries in a set, the methods keys(), values() and entries() are available, as with maps, which can be used to return individual iterators. As sets do not contain keys, the keys() and values() methods return an iterator for the values in the respective set and the entries() method returns an iterator that returns an array with two entries in each iteration, both of which represent the respective value.
Complete Code - Examples/Part_208/main.js...
const cities = new Set(
[
'Tokyo',
'Delhi',
'Cairo',
'New York',
'Berlin'
]
);
for (let city of cities.keys()) {
console.log(city);
}
// output: "Tokyo", "Delhi", "Cairo", "New York", "Berlin"
for (let city of cities.values()) {
console.log(city);
}
// output: "Tokyo", "Delhi", "Cairo", "New York", "Berlin
for (let city of cities.entries()) {
console.log(city[0]); // Value, e.g. "Tokyo"
console.log(city[1]); // Value, e.g. "Tokyo"
}
for (let city of cities) {
console.log(city);
}
// output: "Tokyo", "Delhi", "Cairo", "New York", "Berlin"
2.3. Use Weak Sets
For sets, there is the Weak-Sets alternative, which is represented by the type WeakSet. Here, the objects that are no longer referenced elsewhere are regularly deleted from the set (garbage collection). Weak sets do not provide the keys(), values() and entries() methods, have no size property and no clear() method. And here too, as with weak maps, no prmtive data types can be added as values of a weak set.
Complete Code - Examples/Part_209/main.js...
const city1 = {
name: 'Tokyo'
};
const city2 = {
name: 'Delhi'
};
const city3 = {
name: 'Cairo'
};
const city4 = {
name: 'New York'
};
const city5 = {
name: 'Berlin'
};
const city6 = {
name: 'Paris'
};
const cities = new WeakSet(
[
city1,
city2,
city3,
city4,
city5
]
);
console.log(cities.has(city1)); // output: true
cities.delete(city1); // Delete a value
console.log(cities.has(city1)); // output: false
console.log(
cities.has(city6) // output: false
);
console.log(cities);
Related links: