DEV Community

Cover image for Sets in Javascript ES6
Damien Cosset
Damien Cosset

Posted on

Sets in Javascript ES6

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.

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

const set = new Set([1, 2, 3])
console.log(set) // Set { 1, 2, 3 }
Enter fullscreen mode Exit fullscreen mode

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

const set = new Set([1, 2, 2, 2, 3, 4, 5, 5, 5, 4])
// Set { 1, 2, 3, 4, 5 }
Enter fullscreen mode Exit fullscreen mode

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.

const set = new Set()
set.size // 0
set.add(2)
set.size // 1
Enter fullscreen mode Exit fullscreen mode

add is ignored if the set already has the value:

const set = new Set(['Hello', 'World'])
set.add('Hello')
console.log(set) // Set { 'Hello', 'World' }
Enter fullscreen mode Exit fullscreen mode

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.

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' }
Enter fullscreen mode Exit fullscreen mode

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


Object.is(5, 5) //true
Object.is(5, '5') //false
Object.is({},{}) //false
Enter fullscreen mode Exit fullscreen mode

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
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
Enter fullscreen mode Exit fullscreen mode

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:

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
Enter fullscreen mode Exit fullscreen mode

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:

const set = new Set([1, 2, 3])
const array = [...set]
console.log(array) // [ 1, 2, 3 ]
Enter fullscreen mode Exit fullscreen mode

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.

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) // {}
Enter fullscreen mode Exit fullscreen mode

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 )

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (6)

Collapse
 
nickytonline profile image
Nick Taylor

Thanks for the post Damien. You should do a follow up on Maps, WeakMaps. Maybe go into explaining how Weakmaps are great for meta data.

Collapse
 
damcosset profile image
Damien Cosset

Thank for the comment. I'm working on it ;)

Collapse
 
bernhardwebstudio profile image
Bernhard Webstudio

Thanks for the post. The last example is a little confusing to me: When setting obj = null, and afterwards testing with set.has(obj), I would expect the set to return false even if it still contains {} (the object), as the test is equal to set.has(null) and you never added null to the set. Or am I wrong?

Collapse
 
damcosset profile image
Damien Cosset

In that last example, we added a reference to the object, inside the variable obj. By setting obj to null, we eliminate the last reference to the object we stored in our set. Therefore, because this is a WeakSet, the object is garbage-collected in order to free memory.

Hope it's clear :)

Collapse
 
ben profile image
Ben Halpern

Probably the cleanest cover image you've had Damian! 😋

Collapse
 
math2001 profile image
Mathieu PATUREL

So, if there are no other references to an object, the reference inside the set will disappear.

I never took the time to actually learn what "weak" things were. Thanks :D