Sets are a new object type introduced in ES6 (ES2015). Although they are lesser known, they can be very useful and powerful. This tutorial will help you learn all you need to know about them. You will learn about what sets in JavaScript are, how they work and how to use them.
Introduction to sets
Sets are a new object type that was introduced to JavaScript with ES6 (ES2015). What sets allow you to do is to create collections of values. These values can be anything, from numbers and strings to arrays and objects. This doesn't sound like something exciting. You can do the same thing with arrays.
The thing about sets, and where they differ from arrays, is that they can contain only unique values. When you try to add multiple same values into a set it will accept only the first. Any subsequent same value will be ignored. This also applies to values such as null and undefined. Each will be added only once.
This is one of the reasons why JavaScript developers sometimes choose sets over arrays. When you want to create a collection of some values, and you need all values to be unique, sets are the easiest option.
Creating sets in JavaScript
When you want to create sets in JavaScript you do it always with the set constructor set()
, preceded by the new
keyword. This will create new Set object.
// Create new empty set
const mySet = new Set()
Adding values to sets
When you are creating new set, there are two things you can do. First, you can create new empty Set object and add values to it later. You can add values to a set using add()
method. This method accepts either one value or an iterable. Iterable means an array of values.
So, you can either pass in values one by one, or you can pass in an array with values. Both will work. Remember that set accepts all primitive data types as well as objects.
// Example no.1: Adding a single value
// Create new empty set
const mySet = new Set()
// Add single values to "mySet" set
mySet.add('Helo')
mySet.add(314)
mySet.add(false)
mySet.add(null)
mySet.add(undefined)
mySet.add({ name: 'Joe' })
// Log the value of "mySet"
console.log(mySet)
// Output:
// Set { 'Helo', 314, false, null, undefined, { name: 'Joe' } }
// Example no.2: Adding multiple values
// Create new empty set
const mySet = new Set()
// Add multiple values to "mySet" set vie iterable
mySet.add(['Strike', 13, false, null, [5, 6], { language: 'JS & TS' }])
// Log the value of "mySet"
console.log(mySet)
// Output:
// Set { [ 'Strike', 13, false, null, [ 5, 6 ], { language: 'JS & TS' } ] }
The second option is to add values right at moment you are creating a set. To do this, you have to pass an iterable with some values as a parameter to set constructor. Remember that it is necessary to pass those values as iterable, that is an array. Otherwise, nothing will be added. This applies to both, single and multiple values.
// Create new set and add a single value
const mySetOne = new Set(['Blackout!'])
// Log the value of "mySetOne"
console.log(mySetOne)
// Output:
// Set { 'Blackout!' }
// Create new set and add a single value
const mySetThree = new Set([{ galaxy: 'Milky way' }])
// Log the value of "mySetOne"
console.log(mySetThree)
// Output:
// Set { { galaxy: 'Milky way' } }
// Create new set and add a single value
const mySetFour = new Set([['Andromeda', 'Mayall\'s Object', 'Malin 1']])
// Log the value of "mySetOne"
console.log(mySetFour)
// Output:
// Set Set { [ 'Andromeda', "Mayall's Object", 'Malin 1' ] }
// Create new set and add multiple values
const mySetTwo = new Set(['Entropy', 'atoms', ['gravity', 'space']])
// Log the value of "mySetOne"
console.log(mySetTwo)
// Output:
// Set { 'Entropy', 'atoms', [ 'gravity', 'space' ] }
Notice that when you add values to set when you create it that array will get deconstructed. This means that new Set(['a', 'b'])
will become Set {'a', 'b'}
. See? No array wrapping the values. However, if you add an array inside the outer most array it will remain an array, such as in ['Entropy', 'atoms', ['gravity', 'space']]
.
Removing values from Sets
The easiest way to remove a value from a set is by using delete()
method. This method works in a similar way as the add()
method. You pass the value as an argument when you call this method. If deletion is successful, delete()
will return true
. If not, it will return false
.
One potential downside of this method is that it works only with one value at the time. If you try to pass in multiple values in the form of multiple arguments it will work only partially. The delete()
method will remove only the first value, the first argument, and ignore the rest.
If you try to pass in values in the form of an array. The delete()
method will ignore all values.
// Create new set with some values
const mySet = new Set(['Pegasus', 'Hydra', 'Virgo'])
// Log the value of "mySet"
console.log(mySet)
// Output:
// Set { 'Pegasus', 'Hydra', 'Virgo' }
// Remove some values
mySet.delete('Pegasus')
// Log the value of "mySet" again
console.log(mySet)
// Output:
// Set { 'Hydra', 'Virgo' }
// Try to remove multiple values again using array
// Doesn't work at all
mySet.delete(['Hydra', 'Virgo'])
// Log the value of "mySet" again
console.log(mySet)
// Output:
// Set { 'Hydra', 'Virgo' }
// Try to remove multiple values using multiple parameters
// Removes only the first value passed into delete()
mySet.delete('Hydra', 'Virgo')
// Log the value of "mySet" again
console.log(mySet)
// Output:
// Set { 'Virgo' }
Removing all values from sets
Sometimes, you may want to remove all values from set. This can be done using clear()
method. This method doesn't accept any arguments.
// Create new set
const mySet = new Set()
// Add some values
mySet.add('Centaurus')
mySet.add('Sculptor')
mySet.add('Circinus')
// Log the value of "mySet"
console.log(mySet)
// Output:
// Set { 'Centaurus', 'Sculptor', 'Circinus' }
// Remove all values
mySet.clear()
// Log the value of "mySet" again
console.log(mySet)
// Output:
// Set {}
Checking for existing values in sets
The has()
method is probably the simplest way to test if set contains a specific value. This method accepts a single parameter, value you want to search for. If the value exists, has()
will return true
. Otherwise, it will return false
.
// Create new set with some values
const mySet = new Set(['Jack', 'Andrew', 'Victoria', 'Emma'])
// Check if "mySet" contains "Andrew"
mySet.has('Andrew')
// Output:
// true
// Check if "mySet" contains "Leopold"
mySet.has('Leopold')
// Output:
// false
Finding out how big a set is
When you want to know how many items are in an array, you can use its length
property. Sets don't have exactly this property. However, they have an alternative. This alternative is size
property. It works just like length
property, returns the number all values that exist in a specific set.
// Create new set
const mySet = new Set()
// Log the size of "mySet"
console.log(mySet.size)
// Output:
// 0
// Add some values
mySet.add('Earth')
mySet.add('Mars')
mySet.add('Jupiter')
// Log the size of "mySet" again
console.log(mySet.size)
// Output:
// 3
Sets, keys and values
If you want to find out what values a set contains, there are two methods you can use. Well, it is one method and one alias for the same method. The method is values()
and the alias is keys()
. Using any of these methods will create an iterator object. This iterator contains all values in the order in which you added them to the set.
When you have this iterator you can iterate over all values one by one. If you are not familiar with iterators and generators. When you work with iterator object, you can go to the next value by calling the next()
method. You call this method on the iterator object you created.
// Create new set
const mySet = new Set()
// Add some values
mySet.add('Loki')
mySet.add('Thor')
mySet.add('Freyr')
// Create an iterator object that contains all values
const mySetValues = mySet.values()
// Alternative:
// const mySetValues = mySet.keys()
// Log the value of "mySetValues"
console.log(mySetValues)
// Output:
// [Set Iterator] { 'Loki', 'Thor', 'Freyr' }
// Log the first value
console.log(mySetValues.next().value)
// 'Loki'
// Log the second value
console.log(mySetValues.next().value)
// 'Thor'
// Log the third value
console.log(mySetValues.next().value)
// 'Freyr'
// Log the fourth value
// There are only three values in the set
// that's why the "value" is now "undefined"
console.log(mySetValues.next().value)
// Output:
// undefined
Looping over values with for...of loop
If you don't want use the next()
method to get the values, you can use for...of loop instead. The for...of
loop will help you to loop over the iterator object and get all values one by one automatically.
// Create new set
const mySet = new Set()
// Add some values
mySet.add('Loki')
mySet.add('Thor')
mySet.add('Freyr')
// Create an iterator object that contains all values
const mySetValues = mySet.values()
// Loop over the "mySetValues" iterator object
// and log all values one by one
for (const val of mySetValues) {
console.log(val)
}
// Output:
// 'Loki'
// 'Thor'
// 'Freyr'
Getting all entries in a set
Aside to the values()
and keys()
methods, you can also access all values inside a set with entries()
method. Similarly to values()
and keys()
, this method also creates an iterator object containing all entries. You can then iterate over this object using either next()
method or for...of
loop.
// Create new set
const mySet = new Set()
// Add some values
mySet.add('MSFT')
mySet.add('AAPL')
mySet.add('BABA')
mySet.add('ADBE')
mySet.add('DELL')
// Create an iterator object that contains all entries (values)
const mySetEntries = mySet.entries()
// Loop over the "mySetValues" iterator object
// and log all values one by one
for (const entry of mySetEntries) {
console.log(entry)
}
// Output:
// [ 'MSFT', 'MSFT' ]
// [ 'AAPL', 'AAPL' ]
// [ 'BABA', 'BABA' ]
// [ 'ADBE', 'ADBE' ]
// [ 'DELL', 'DELL' ]
// Or using next() method
// Log the first value
console.log(mySetEntries.next().value)
// Output:
// [ 'MSFT', 'MSFT' ]
// Log the second value
console.log(mySetEntries.next().value)
// Output:
// [ 'AAPL', 'AAPL' ]
// Log the third value
console.log(mySetEntries.next().value)
// Output:
// [ 'BABA', 'BABA' ]
// Log the fourth value
console.log(mySetEntries.next().value)
// Output:
// [ 'ADBE', 'ADBE' ]
When you use the entries()
method the format for each entry will be [ key, value ]
. What may surprise you is that the key
and value
in this entry array will be the same. You could see this on the example above. Don't worry about this. This is how the entries()
method was implemented in JavaScript.
Iterating over sets with forEach()
The for...in
loop is not the only way to iterate over a set. You can also use forEach()
method. This might be even easier and faster than using for...in
loop.
// Create new set
const mySet = new Set(['JavaScript', 'Python', 'Ruby', 'Perl'])
// Use forEach() to iterate over "mySet"
// and log all existing values
mySet.forEach(val => {
console.log(val)
})
// Output:
// 'JavaScript'
// 'Python'
// 'Ruby'
// 'Perl'
Conclusion: Introduction to sets in JavaScript
Sets can be useful and powerful tool in a toolkit of every JavaScript developer. They can be a handy alternative to arrays and maps. I hope this tutorial made it easier for you to understand what sets in JavaScript are, how they work and, most importantly, how to use them.
Top comments (9)
Great write up! I'm very excited about the set in JS now.
The missing piece right now IMO is set operators. In Python, for example, you can do
set1.difference(set2)
MDN has some simple functions that provide this functionality under the "Implementing basic set operations" header of their docs. So useful!
developer.mozilla.org/en-US/docs/W...
I end up looking up this page often when using sets in JS. Good share.
Thanks Andrew. These operators could bring sets more to the forefront. Who knows, maybe they are somewhere on the JS road map.
I'm puzzled why
entries()
return an array for each element, containing the same thing twice. What's the use of that?This is just a guess. It could be for compatibility reasons. Objects (literals) contain data in the form of key-value pairs. The
entries()
should return both, key and value. Sets contain only values. Adding duplicates can be a way to make the result ofentries()
and its format consistent.Hey Alex,
Awesome, really a full write-up on Set, lovely to use.
Thank you.
Good article. It's useful if you are working with primitive types often. But with objects I don't see many use cases.
Thanks Barney. Agree, there are not many things you could do only with sets. For the most part, objects, arrays or maps will do the job.