Sets in Javascript ES6
Tags: javascript
Published: 2018-07-11 19:59:38

---
title: Sets in Javascript ES6
published: true 
description: Exploring Set and WeakSet from ES6
cover_image: https://cdn-images-1.medium.com/max/640/1*SL4sWHdjGR3vo0x5ta3xfw.jpeg
tags: javascript
---

## Introduction

Before ES6, Javascript had no native implementation of Sets. What is a set? A set is a list of values that cannot contain duplicates. Let's explore what problems that native ES6 Set solves, and how we can use them.

###  Constructor


To create a new set, we can use `new Set()`. You can also give an iterator directly in the constructor. 

```javascript
const set = new Set()
console.log(set) // Set {}

const set = new Set([1, 2, 3])
console.log(set) // Set { 1, 2, 3 }
```

If you give an iterable with duplicates, the Set will ignore the duplicates after the first one:

```javascript
const set = new Set([1, 2, 2, 2, 3, 4, 5, 5, 5, 4])
// Set { 1, 2, 3, 4, 5 }
```

### The *add* method and *size* property

Sets have an *add* method that allow you to add a single item to the set. Sets also have a *size* property to retrieve the number of items in the set.

```javascript
const set = new Set()
set.size // 0
set.add(2)
set.size // 1
```

*add* is ignored if the set already has the value:

```javascript
const set = new Set(['Hello', 'World'])
set.add('Hello')
console.log(set) // Set { 'Hello', 'World' }
```

### Problems solved from workarounds

Before sets, you would have to use normal objects to simulate a set. Because only strings can be use as keys, some problems could arise. 5 would be coerced into "5", {} would be "[object Object]". Sets do not coerce values. 5 and "5" are two different values.

```javascript
const set = new Set()
set.add({})
set.add({})

set.size // 2
console.log(set) // Set { {}, {} }

set.add(5)
set.add('5')
set.add(5) // this will be ignored

set.size // 4
console.log(set) // Set { {}, {}, 5, '5' }
```

Therefore, multiple objects can be added to the set. Sets use `Object.is()` to compare two values:

```javascript

Object.is(5, 5) //true
Object.is(5, '5') //false
Object.is({},{}) //false
```

### The *has*, *delete* and *clear* methods

- *has(value)* checks if the value is in the set. Returns true or false
- *delete(value)* removes the value from the set
- *clear()* removes all values from the set

```javascript
const set = new Set()
set.add(5)

set.has(5) // true
set.has(8) // false

const set = new Set([1, 2, 3])
set.size // 3
set.delete(2)
set.size // 2
set.clear()
set.size // 0
```

### Iteration

To iterate through a set, you can use the forEach() method. There is one little difference from when you are using it on an object/array. forEach() takes three arguments:

- the value
- the key ( index )
- the array or object your are iterating

However, in a set, the first two arguments are the same. That is because sets don't have keys. So:

```javascript
const set = new Set([1, 2, 3])
set.forEach((value, key, s) => {
	console.log(`${value} ${key}`)
	console.log( set === s)
})

//1 1
//true
//2 2
//true
//3 3
//true
```

That way, you can use the same method that you already used for arrays and objects.

### Set => Array

We already saw that you can convert an array to a set by passing an array to the Set constructor. You can also convert a set to an array by using the spread operator:

```javascript
const set = new Set([1, 2, 3])
const array = [...set]
console.log(array) // [ 1, 2, 3 ]
```

### Weak sets

These sets could be called *strong* sets, because it holds object references. It works as if you would store an object inside a variable. As long as the set instance exists, the object can't be garbage-collected in order to free memory.

```javascript
const set = new Set()
let obj = {}

set.add(obj)
set.size // 1
obj = null
set.size // 1

// We can retrieve the original reference
obj = [...set][0]
console.log(obj) // {}
```

In some cases, you do want references in a set to disappear if all the other references disappear. ES6 includes weak sets. Weak sets can only store weak object references. So, if there are no other references to an object, the reference inside the set will disappear. WeakSet also cannot contain primitive values ( no strings or integers )

```javascript
const set = new WeakSet()
let obj = {}

set.add(5) // ERROR
let obj = {}
set.add(obj)
set.has(obj) // true
obj = null // remove the reference to obj, also removes it in set
set.has(obj) // false
```

WeakSets:

- will throw errors if you pass nonobjects to *add()*, *has()* or *delete()*.
- are not iterables. You can't use for-of or the forEach() method.
- do not have a size property.

The *limited* functionality of weak sets is necessary to properly handle memory.

## Conclusion

ES6 gives you a new way to create sets and solves a lot of ES5 issues with the workarounds developers used. Use weak sets if you only need to track object references and prevent memory leaks.