It's safe to say that arrays and objects are JavaScript's most useful, popular, and overused collections. However, there are cases where neither of them solves your problem effectively, or their limitations are getting in the way, thus making your solution more complex than it should be.
In this article, I'll discuss everything you need to know to leverage sets, maps, and their unique features to solve complex data structure problems.
Prerequisites
To follow this tutorial, you need to understand JavaScript. It'll help if you also know one or two limitations of arrays and objects.
In the next section, we’ll explore sets and how to use them.
Sets
A set is a type of JavaScript collection that can store all supported types in JavaScript, including object references.
A set is unordered, cannot contain duplicate values, and has rapid access to the data it contains.
There are two common ways to create a set in JavaScript. The first is passing an array to the constructor:
const ids = new Set(['ADM78921', 'ADM78921', 'ADM73212', 'ADM70213']);
console.log(ids);
The image above shows the set in the console; notice that the duplicate value was stripped out of the result.
The second common way to create an empty set and use the chainable add
method to add values:
const ids = new Set()
.add('ADM78921')
.add('ADM73212')
.add('ADM70213')
.add('ADM78921')
console.log(ids);
The code above will return the same result as the previous image.
As mentioned earlier, a set can contain any value. Here is an example:
const hobbies = ["singing", "dancing", "horse riding"]
const diffValSet = new Set()
.add(5)
.add('5')
.add({name: "Adams", age: 22, occupation: "Software Developer"})
.add(hobbies)
console.log(diffValSet)
The code above creates a set named diffValSet
and will return the result:
We’ll look at some of the most common set methods in the next section.
Set Methods
The set
collection comes with very helpful methods that make working with the collection easy. Let's look at some of the methods.
Adding New Values
You can use the add
method to add new values to the set:
ids.add('ADM75209');
ids.add('ADM75209');
console.log(ids)
The code above adds a new string value to the set and returns the following result:
Note: The value
ADM75209
was only added once, even though I called theadd
method with the same value twice.
Let's see how to count the values in a set next.
Counting Values
Sometimes, you might want to limit your set to a specific number of values.
You can get the number of values in your set using the size
property:
console.log(diffValSet.size) // returns 4
We’ll look at how to loop through sets in the next section.
Looping Through Sets
Iterating values is almost unavoidable when developing apps and websites. You can loop through sets by using the forEach
method:
const winnersIds = new Set(['ADM78921', 'ADM73212', 'ADM70213', 'ADM75209', 'ADM75119'])
winnersIds.forEach((value)=>{
console.log(`${value} won`)
})
The code above creates a winnersIds
set and then loops through it using the forEach
method. The code above should produce the following result:
Notice how the values came out the same way they were inserted upon creation.
We’ll look at how to delete values from sets next.
Deleting Values
You can delete an existing value from a set by calling the delete
method on the set:
diffValSet.delete(5)
console.log(diffValSet)
The code above will delete the number 5
from the diffValSet
set:
Note: You can only delete one value simultaneously using the
delete
method. That means trying to delete multiple values likediffValSet.delete(5, hobbies)
would not work.
However, deleting objects like the one inside diffValSet
is not as straightforward, so you need to use a loop hack with the forEach
method:
diffValSet.forEach(item => { if (item.age === 22) diffValSet.delete(item); });
The code above will loop through the set, check for any key inside the object, and delete the whole object if the condition is true.
Next, let's look at how to check whether a value exists in a set.
Checking values
It is considered good practice to check whether a value exists in your code before deleting or adding a new value.
To check if the value exists in a set, you can use the has
method:
console.log(diffValSet.has(hobbies)) // returns `true`
The code above will return true
because hobbies
exists in the diffValSet
set.
Let's see how to delete all the values in a set.
Clearing a Set
Sometimes, you might want to delete all the values in the set at once.
You can do that with the clear
method:
diffValSet.clear()
console.log(diffValSet)
The image above shows the size of the set as 0
after running the clear
method on it.
Next, let's see the difference between sets and arrays.
Differences between Sets and Arrays
In the previous sections, you learned what sets are, how to use them, and the common set methods.
This section will show you the common differences between sets and arrays.
Unique values
As you have learned in the previous section, sets can only contain unique values, unlike arrays, which can contain duplicate values. You can remove duplicates from arrays by putting them inside a set:
const topWebsites = ['google.com', 'facebook.com', 'twitter.com', 'youtube.com', 'google.com', 'quora.com']
const uniqueSites = new Set(topWebsites)
console.log(uniqueSites)
The code above declares a topWebsites
that has duplicate values and converts it to a uniqueSites
set that strips out the duplicate google.com
values from the topWebsites
:
The image above shows a set that contains unique values.
You can convert the uniqueSites
set back to an array using the spread operator:
console.log([...uniqueSites])
The code above will return the uniqueSites
as an array:
Accessing Values
When using arrays, you can access values inside the array using the index:
const proteins = ['beef', 'pork', 'chicken', 'egg', 'bacon']
console.log(arr[2]) // returns 'chicken'
The code above declares a proteins
array and logs the item's value in the second index to the console.
What I just demonstrated above is impossible when using sets because the index is the same as the value, so you need to know the value to retrieve it from the set.
You can use the has
method to check this.
Order of Insertion and Deletion
Unlike arrays, where you can insert and delete items in a specific index, sets only add new items to the end of the set using the add
method and deletes an item by referencing the value using the delete
keyword, as you saw earlier.
Those are the significant differences between sets and arrays in JavaScript.
Next, let's look at WeakSets and how to use them.
WeakSets
A WeakSet
is a collection type that is similar to Sets
, but it can only contain objects and is automatically garbage-collected. The most notable difference between Sets
and WeakSets
is that WeakSets
only has three methods, called add
, has
, and delete
, and they work the same way they do on sets.
Let's look at how to create a WeakSet
next.
Creating a WeakSet
The easiest way to create a WeakSet
is by using the new
keyword:
const winners = new WeakSet([{1: '@logan'}, {2: '@mekako'}, {3: '@oddone'}])
The code above declares a WeakSet
that contains three objects:
Another way to declare a WeakSet
is to put object references inside the square brackets:
const person = {name:"Jane", age: 18}
const school = {name: "Griffiths High School", town: "Maryland"}
const home = {streetNo: "12b", streetName: "Westend", town: "Osapa London"}
const userDets = new WeakSet([person, school, home])
console.log(userDets)
The code above declares three different objects and then creates a WeakSet
that includes the three object references:
The significant differences between sets and weaksets are automatic garbage collection and the number of methods.
We’ll see what Maps
are in the next section.
Maps
A map is a JavaScript collection that allows you to store key-value pairs, where the keys can be any value, unlike objects, where the keys can only be strings
, integers
, and symbols
. Keys in a map are also unique and can only appear once in the collection.
Creating Maps
The easiest way to create a map collection is to use the new
keyword with an array of values:
const num = {
num: 1
}
const refs = new Map([
[{num: 1}, "one"],
[[2], "two"],
["iii", "three"]
]);
console.log(refs);
The code above creates a refs
map that contains three values and then logs it to the console. The code above will return the following result:
The result is an object with three values with different values as the key: an object, an array, and a string.
If you add another value with an existing key, JavaScript will change the value of the previous key, and the object will remain in the same position. Add the following line to the previous map:
const refs = new Map([
// same as previous
[2, "three"],
]);
console.log(refs);
The code above adds a value that has the existing 2
key to the previous map, and the result should look like this:
Notice that the image above shows the 2
key in the same position but with a different value of "three"
.
We’ll look at the common map methods in the next section.
Map Methods
Like set
, the map
collection also has some handy methods that help developers quickly get things done with them. In this section, I'll show you the different methods you can use on the map
collection.
The set
Method
Most times, you want to add values to the map dynamically, you can do that using the chainable set
method:
const refs = new Map()
refs.set({num: 1}, "one").set(2, "two").set("iii", "three")
console.log(refs)
The code above creates a refs
map collection and uses the set
method to add values to it. The result should look like this:
Let's see how to get a single value out of a map.
The get
Method
To get the value of a particular key inside the map, you can use the get
method:
console.log(refs.get("iii"))
The code above should return "three"
, which is the value of the iii
key inside the map.
Note: You cannot get multiple values from a
map
by adding multiple parameters to theget
method. For example,console.log(refs.get("iii", 2));
will not work and will only return"three"
instead of"three"
and"two"
The has
Method
As mentioned previously, checking whether a value already exists in a collection is considered good practice before adding or deleting it. The has
method allows you to check if a map contains the given value:
console.log(refs.has(2)) // returns true
The code above will return true
because the map contains the value 2
.
Next, let's see how to loop through maps.
The forEach
Method
You can loop through maps using the forEach
method:
const que = new Map()
que.set(223, "John Sanders").set(421, "Rebecca Stans").set(908, "Wanjiku Kenyamo")
que.forEach((value, key)=>{
console.log(`${key}: ${value}`)
})
The code above declares a que
map with three key-value pairs and then uses the forEach
to loop through the map and log the keys and values to the console.
The forEach
method gives you access to the values and keys inside the map. The code above should return the following:
Next, let's see how to delete a value from a map.
The delete
Method
To dynamically delete a value from a map, you must use the delete
method:
console.log(que.delete(223)) // returns true
console.log(que.delete(23)) // returns false
The code above deletes the 223
value and returns true
upon deletion and false
if the value doesn't exist in the map:
In the next section, let's look at how to clear all the values inside a map.
The clear
Method
Maps in JavaScript come with a clear
method that allows you to delete all the values in a map in one go:
console.log(que.size) // returns number of values
que.clear() // deletes all the values
console.log(que) // logs the now empty map
The code above checks the size of the que
map, deletes all the values in the map using the clear
method, and then logs the now-empty map to the console:
Next, let's see how to get all the entries, keys, and values in the map.
The entries
, keys
, and values
Methods
The map collection in JavaScript comes with the keys
and value
methods, and both return an iterable object that contains a MapIterator
:
console.log(que.values())
console.log(que.keys())
The code above will log all the values and keys in the map to the console:
The entries
method works a bit differently because it returns the keys and values in one iterable object:
console.log(que.entries())
The code above will log both the values and keys in the map to the console in one go:
Converting entries
, keys
, and values
to Arrays
Sometimes, you might need just the keys
, values
, or even entries
of a map as an array because they return iterable objects by default.
You can use the spread operator to convert them to arrays:
console.log([...que.entries()]) // returns a two-dimensional array
console.log([...que.keys()]) // returns an array of the keys
console.log([...que.values()]) // returns an array of the values
The code above converts and logs the keys
, values
, and entries
of the map to the console:
The image above shows the keys
, values
, and entries
as arrays in the console; the entries
is converted into three arrays containing each item's key and value.
Now that you know how to use a map and its methods let's see the differences between maps and objects in JavaScript.
Differences Between Maps and Objects
This section will teach you about the significant differences between maps and objects.
Key Types
As you learned in the previous sections, you can use any type in JavaScript as a key in maps, unlike objects that only allow strings, integers, and symbols.
Order of Insertion
Items in maps maintain their order of insertion; when performing operations like iterations, the items inside maps come out in the order they were inserted, but this is not the case with objects.
Iterating Values
As you saw earlier, you can use the forEach
loop function directly on maps; this is not possible with objects, as they are not iterable by default and can only be iterated using the for...in
loop.
These are the significant differences between maps and objects, but there are other differences in how maps and objects are used, such as adding items, checking items, deleting items, and more.
We’ll look at WeakMaps in the next section.
WeakMaps
A WeakMap
is very similar to Map
, with the only significant difference being that a WeakMap
can only contain objects as keys and supports automatic garbage collection.
A WeakMap
also has the set
, has
, get
, and delete
methods that work the same as they do on a Map
.
Creating WeakMaps
You can create a WeakMap
using the new
keyword:
const type = {
name: "car",
}
const carWM = new WeakMap()
// the set method
carWM.set(type, "Honda");
console.log(carWM)
The code above creates a type
object, creates an empty WeakMap
called carWM
, and uses the set
method to add a "Honda"
value with the type
object as the key. Then, it logs the carWM
to the console. The result should look like this:
WeakMaps also support the get
, has
, and delete
methods the same way Maps do.
Conclusion
In this article, you learned about Sets, WeakSets, Maps, and WeakMaps, their methods, and how to use them in JavaScript. You also learned the differences between Sets and Arrays, as well as the differences between Maps and Objects.
I hope you now understand how these collection types work in JavaScript, and I also hope this article will help you make informed decisions when deciding when to use them instead of arrays and objects.
That was a long ride! Thank you so much for reading!