This article was originally written by Adebayo Adams on the Honeybadger Developer Blog.
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
ADM75209was only added once, even though I called theaddmethod 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
deletemethod. 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
mapby adding multiple parameters to thegetmethod. 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!















Top comments (0)