JavaScript Collections – Set and Map

 Introduction

In this post we will get familiar with two different collections in JavaScript:

  • Set
  • Map

In one of the next posts we will also talk about two similar collections:

  • WeakSet
  • WeakMap

 

They were all introduced to JavaScript spec with ES2015, also known as ES6.

Both Map and Set are iterable types. Just like String and Array are. That means that we can use for…of statement to go iterate these collections and get access to each of their elements.

 

Set

Set is basically a collection of unique values that may be of any type. That literally means you can put any value inside of the set and yes, you can mix types inside of the set, just like with regular JavaScript arrays. I don’t see that being overly useful, but you can do it.

This collection is similar to HashSet in C# world and Set/HashSet in Java.

Official docs quote following syntax:

new Set([iterable]);

iterable
If an iterable object is passed, all of its elements will be added to the new Set. If you don’t specify this parameter, or its value is null, the new Set is empty.

That seems pretty straightforward. In short and simplified words, iterable is something that we can iterate through, and it’s usually a sequence or collection of elements. If you wanna read more about iterators and iterables check out this post – JavaScript Iterators.

Let’s see an example of Set:

Since Set itself is iterable, we can use for..of statement directly against it:

As we said, values inside of Set are unique. If we try to add a value that already exists in the Set it will be simply ignored:

This will not work and the value will not be added.

Set has a very useful property called size which gives us info about a number of values inside of the collection.

Most important methods present on an instance of the Set:

  • add(element) – Adds a new element to the Set
  • clear() – Deletes all elements from the Set
  • delete(element) – Deletes an element from the Set
  • forEach – This is like classic forEach loop for an array
  • has(value) – Returns true if the collection contains given element.
  • toString() – Prints out “[object Set]”
  • values() – Returns all the values of the Set collection
  • keys() – Same as values() really. It is an alias for values() method. Only reason it exists is to have uniform interface accross new collection types in JavaScript.

 

forEach on Set

Syntax:

mySetInstance.forEach(function callback(value1, value2, Set) {
   // some code that will be run for every value inside ofSet
}[, thisArg])

If you are familiar with the syntax of forEach for JavaScript Array, you will notice it has the same signature. Except that with the array we have an index as the second argument.

For the record, Map also uses the same syntax, however, the second argument is the key.

Since Set does not have keys or indexes its second callback argument is the value. So, the same syntax for Set callback was done in order for these collections to have the consistent syntax.

The first two Arguments of the callback value1 and value2 are literally the same and they represent a value inside of Set.

The third argument represents the Set object that is being traversed.

 

Get an Array from existing Set

We can simply convert Set to Array by making use of destructuring:

Get unique values from Array by using Set

As we said, Set is a collection that has unique values, meaning that it can’t have duplicates. We just saw how we can get an Array from Set and before we saw that we can make a Set from Array (or any iterable). Let’s make use of that!

Example:

That’s neat and it definitely can be handy for filtering out arrays and getting unique values.

 

Map

Map is basically a collection of key/value pairs. This is similar to Dictionary in C#, Map in Java and Hash in Ruby.

Map also has a property called size which gives us info about a number of keys/values inside of the collection.

Following methods are present on an instance of the Map:

  • clear() – Deletes all elements from the Map
  • delete(key) – Deletes an element from the Map
  • forEach – This is like classic forEach loop for an array
  • get(key) – Gets the element for the specified key
  • has(key) – Returns true if the collection contains an element that has this key
  • keys() – Returns all the keys of the Map collection
  • set(key, value) – Adds a new element to the map
  • values() – Returns all the values of the Map collection
  • toString() – Prints out “[object Set]”

Here is an example of new Map object being instantiated:

We can also go through the list of keys or values:

These will print out different values:

The first line will print out 55 and the second line will print out 44 because we provided different keys.

I hope you are wondering if there is a way to simply print out all keys or values of given Map instance. Yes, there is!

We can use the handy Array.from method:

The last one will simply print out the same array we provided when we made an instance of the Map. Well, it is an array that has arrays as elements.

 

Map vs Object

You are probably wondering why would we use Map if we can simply use JavaScript’s objects. They are also very similar to Map, we got keys and values for those keys.

  • Well, with Map we got some handy built-in methods and also the size property to easily determine how many values are we storing inside of Map.
  • You should be using Map when you know you will be adding values to it in the run-time.
  • For regular access and often updates to the records, using object or array is probably easier. With Map you have to user .get() and .set() methods.
  • Anything can be a key in Map while with regular objects we have to use strings as keys. If we use something else as a key, that will be converted to the string and then used as a key.

Also, every object has some keys already while Map instance has no keys/values by default. Let’s see an example:

But of we course we can make use of built-in hasOwnProperty method to check if the key is really on object or it’s on oneof the prototypes. Also, we usually use Object.keys() method to get only own and enumerable keys of given object.

 

Summary

  • We can make use of Sets to get unique values for Arrays. However, we can also keep using Sets once we turn array into a Set
  • We can easily convert from Sets to Arrays and another way around.
  • Maps are useful when we want to use keys that are not necessarily strings.
  • Useful tips when you are considering whether to use Map or regular objects
    • Use maps over objects when keys are unknown until run-time, and when all keys are the same type and all values are the same type.

    • You should use maps in case if there is a need to store primitive values as keys because object treats each key as a string whether it’s a number value, boolean value or any other primitive value.

    • Use objects when there is logic that operates on individual elements.

Ibrahim Šuta

Software Consultant interested and specialising in ASP.NET Core, C#, JavaScript, Angular, React.js.