How to use Map and Set in ES6 Javascript
Tags: beginners, javascript
Published: 2020-07-05 15:02:01

Sets and maps are two new standard collection types included in ES6.

Sets are very similar to Arrays, but they don't come with all the fancy built in methods that Arrays have. However, they do have some advantages, one of which is that they enforce uniqueness.

Maps are similar to Objects, except they too are lacking all the fancy built in methods. But, just like Sets, they also have advantages. For example, Maps allow any data type to be set as a key, not just a string.

## Sets

Unlike Arrays, Sets are constructed with hash tables, so most of their operations have a time complexity of O(1), which means they are generally faster than Arrays. [[Javascript Set vs. Array performance]]

```javascript
const names = new Set();

//.add() adds a value to the set
names.add('John');
names.add('Paul');
names.add('Daniel');

//.remove() removes a value from the set
names.remove('John');

//.has() returns whether a value is in the set
names.has('Paul'); // returns true
```

The most interesting feature of Sets really comes into play when you build a few helper functions for them. Because remember, they enforce uniqueness. So let's say you wanted to join two arrays without accruing any duplicates.

Just add all the elements in one Set into the other and they will automatically not add any duplicates!
```javascript
const setOne = new Set(['Caylie', 'Bob', 'Danny']);
const setTwo = new Set(['Caylie', 'John', 'Sarah']);

const union = (setA, setB) => {
  const finalSet = setA;
  setB.forEach(item => { finalSet.add(item); });
  return finalSet;
}

union(setOne, setTwo); // returns Set {'Caylie', 'Bob', 'Danny', 'John', 'Sarah'};
```
Or maybe you just want to get the elements that are shared by two Sets.

Just make a new Set and check every element in one Set and only add it to the new Set if it's in the other Set!
```javascript
const setOne = new Set(['Caylie', 'Bob', 'Danny']);
const setTwo = new Set(['Caylie', 'John', 'Sarah']);

const intersection = (setA, setB) => {
  const finalSet = new Set();
  setA.forEach(item => { if(setB.has(item)) finalSet.add(item); });
  return finalSet;
}

intersection(setOne, setTwo); // returns Set {'Caylie'};
```

Or perhaps you just want to get the elements that are not shared by two Sets.

Just make a new Set based on one of the Sets and then check every element in the other Set. If the new Set has it, remove it, if it doesn't have it, add it!
```javascript
const setOne = new Set(['Caylie', 'Bob', 'Danny']);
const setTwo = new Set(['Caylie', 'John', 'Sarah']);

const difference = (setA, setB) => {
  const finalSet = new Set(setA);
  setB.forEach(item => {
    if(finalSet.has(item)) finalSet.delete(item);
    else finalSet.add(item);
  });
  return finalSet;
}

difference(setOne, setTwo); // returns Set {'Bob', 'Danny', 'John', 'Sarah'};
```
A Set's real strength is in enforcing uniqueness on it's elements, so I've got one last quick trick for you to remember about Sets.
```javascript
const arr = [1, 2, 3, 4 ,5, 1, 2, 3, 4 ,5, 6, 6, 6];
const uniqueArr = [...new Set(arr)]; // [1, 2, 3, 4, 5, 6]
```
Getting an Array to only contain unique elements is as easy as converting it to a Set and then just converting it right back to an Array, as you can see in the above example. And it's faster than reduce or filter!

## Maps
Maps mostly behave just like Objects, except that they have some different methods. And they can store any datatype as a key, not just a string. So all of the below examples are perfectly valid key value pairs in a map.
```javascript
const newMap = new Map();
const newObj = { name: 'Bob' };
const newFunc = () => {};

newMap.set(true, 'this key is the value true');
newMap.set(newFunc, 'this one is a function');
newMap.set(newObj, 'and this one is an object');

console.log(newMap) // Map { true => 'this key is the value true',
                    //       function newFunc() => 'this one is a function',
                    //       { name: 'Bob' } => 'and this one is an object' }
```

The real advantage that Maps have over Objects is in the way you can iterate over them. In the following example we make a Map that has a guest coming to our party as its keys and the food they are bringing as its values.
```javascript
const guests = new Map();
const bob = { fName: 'Bob', lName: 'Smith' };
const john = { fName: 'John', lName: 'Sanders' };
const april = { fName: 'April', lName: 'Jones' };
guests.set(bob, 'Cobb Salad');
guests.set(john, 'Chips and Dip');
guests.set(april, 'Brisket');

for (let key of guests.keys()){
  console.log(key.fName); // 'Bob', 'John', 'April'
}

for (let value of guests.values()){
  console.log(value); // 'Cobb Salad', 'Chips and Dip', 'Brisket'
}

for (let [key, value] of guests.entries()){
  console.log(`${key.fName} ${key.lName} is bringing ${value}`);
  // 'Bob Smith is bringing Cobb Salad'
  // 'John Sanders is bringing Chips and Dip'
  // 'April Jones is bringing Brisket'
}
```
As you can see it's a little easier to iterate over a Map than an Object, but unfortunately Maps can't be easily converted to JSON like Objects can. So most of the time, even though they have some fun tricks, you should probably just keep using Objects.

While Set and Map have some unique functionality that make them very good in very specific circumstances, they aren't really doing anything that an Array or an Object can't. So most of the time you should probably just keep using Arrays and Objects....

except....
```javascript
const uniqueArr = [...new Set(arr)];
```

[Javascript Set vs. Array performance]: https://stackoverflow.com/a/39010462