Advanced Javascript Collections: Introduction to Sets and Maps
Tags: javascript
Published: 2023-06-28 15:53:02

*This article was originally written by [Adebayo Adams](https://www.honeybadger.io/blog/authors/adebayoadams/) on the [Honeybadger Developer Blog](https://www.honeybadger.io/blog/javascript-sets-and-maps/).*

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:

```js
const ids = new Set(['ADM78921', 'ADM78921', 'ADM73212', 'ADM70213']);
console.log(ids);
```

![set without duplicate](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/set_without_duplicate.png)

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:

```js
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:

```js
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:

![multiple types set](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/multiple_types_set.png)

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:

```js
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:

![add method example result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/add_method_example_result.png)

> Note: The value `ADM75209` was only added once, even though I called the `add` 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:

```js
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:

```js
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:

![loop result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/loop_result.png)

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:

```js
diffValSet.delete(5)
console.log(diffValSet)
```

The code above will delete the number `5` from the `diffValSet` set:

![delete value result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/delete_value_result.png)

> Note: You can only delete one value simultaneously using the `delete` method. That means trying to delete multiple values like `diffValSet.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:

```js
 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:

```js
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:

```js
diffValSet.clear()
console.log(diffValSet)
```

![clear set result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/clear_set_result.png)

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:

```js
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`:

![array conversion](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/array_conversion.png)

The image above shows a set that contains unique values.

You can convert the `uniqueSites` set back to an array using the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax):

```js
console.log([...uniqueSites])
```

The code above will return the `uniqueSites` as an array:

![set to array conversion](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/set_to_array_conversion.png)

### Accessing Values

When using arrays, you can access values inside the array using the index:

```js
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](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)). 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:

```js
const winners = new WeakSet([{1: '@logan'}, {2: '@mekako'}, {3: '@oddone'}])
```

The code above declares a `WeakSet` that contains three objects:

![weakset](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/weakset.png)

Another way to declare a `WeakSet` is to put object references inside the square brackets:

```js
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:

![weakset references](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/weakset_references.png)

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:

```js
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:

![a map collection](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/a_map_collection.png)

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:

```js
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:

![duplicate values](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/duplicate_values.png)

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:

```js
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:

![set method result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/set_method_result.png)

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:

```js
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 the `get` 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:

```js
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:

```js
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:

![map loop result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/map_loop_result.png)

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:

```js
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:

![delete result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/delete_result.png)

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:

```js
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:

![clear map result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/clear_map_result.png)

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`:

```js
console.log(que.values())
console.log(que.keys())
```

The code above will log all the values and keys in the map to the console:

![values and keys result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/values_and_keys_result.png)

The `entries` method works a bit differently because it returns the keys and values in one iterable object:

```js
console.log(que.entries())
```

The code above will log both the values and keys in the map to the console in one go:

![entries method result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/entries_method_result.png)

### 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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to convert them to arrays:

```js
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:

![array conversion result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/array_conversion_result.png)

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:

```js
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:

![create weakmap result](https://www.honeybadger.io/images/blog/posts/javascript-sets-and-maps/create_weakmap_result.png)

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!