A set in JavaScript is a collection of unique values of any data type. The set data type was added in the EcmaScript version 6(ES6).
To create a JS set, Set
constructor is used. We can optionally pass an iterable object to the Set
to add the elements of that iterable(often an array) object to the set.
const names = new Set(['John', 'Doe', 'Mary', 'Alice']);
console.log(names.size); // 4
We can add elements to the set with the help of add
method.
const cities = new Set();
cities.add('Rome');
cities.add('Tokyo');
console.log(cities.size); // 2
The reason why we're just logging or printing the size of the sets is that we may not see the elements of the set just by logging directly. When we try to log it on the console, we could just see something like Set {}
or [object Set] { ... }
etc based on the environment.
A Set
instance has got various methods for reading and manipulating the data inside it. It's an iterable and so by using iterative methods or loops we can read the data.
The various methods that we can use on sets are:
add()
- to add elements to the sethas()
- to check if the set has a particular elementdelete()
- to delete the element if it existsclear()
- to clear/delete all the elements of the setvalues()
- to get the iterator of values inside the setkeys()
- same as values(). It is there just to match the methods with the map data typeentries()
- to get an iterator with [key, value] elements and in a set keys and values are the same. It also exists to match with the methods of the map data typeforEach()
- to call/invoke a callback function on every element in a setsize
- to get the total number of elements in a set
Let's understand each method with examples
Javascript set methods
add() method
const colors = new Set(); // Initializing an empty set
colors.add('green');
colors.add('blue');
colors.add('red');
console.log(colors.size); // 3
As we know that instance of Set
returns an iterable, so we can use for-of loop as discussed in the previous article to read the values of an iterable.
for(const color of colors) {
console.log(color)
}
// Logs: green, blue, red
has() method
const colors = new Set('green', 'blue', 'red');
// Checks if the elements exists in the set and returns a boolean
colors.has('red'); // true
colors.has('violet'); // false
delete() method
const colors = new Set(['green', 'blue', 'red']);
// Deletes the exact given element if it exists
colors.delete('red');
console.log(colors.size); // 2
clear() method
const colors = new Set(['green', 'blue', 'red']);
// Clears or deletes all the elements in a set
colors.clear();
console.log(colors.size); // 0
values() and keys()
In the case of a JS set, keys()
and values()
methods return the same kind of iterator for iterating the values in a set. The main reason for having keys()
method is to have similar methods as that of a Map
data type in Javascript.
const colors = new Set(['green', 'blue', 'red']);
// values() and keys() return the same
for(const color of colors.values()) {
console.log(color)
}
// Logs: green, blue, red
for(const color of colors.keys()) {
console.log(color)
}
// Logs: green, blue, red
entries() method
The set entries()
method is similar to the Object.entries()
, where it returns keys and values of an object as an array of arrays. In the case of set entries()
method, an iterator with [key, value]
arrays is returned where keys and values are the same.
Object.entries(object)
returns an actual array of arrays butset.entries()
returns an iterator with [key, value] arrays.
const colors = new Set(['green', 'blue', 'red']);
for(const color of colors.entries()) {
console.log(color)
}
// Logs: ["green", "green"], ["blue", "blue"], ["red", "red"]
forEach() method
The set forEach
method works the same as the forEach
method on arrays. It allows running a callback function on every element of the set.
const colors = new Set(['green', 'blue', 'red']);
colors.forEach(c => console.log(c));
// Logs: green, blue, red
size property
The size property of a Set
instance returns the total number of elements present inside the set, nothing but the length of the set.
const colors = new Set(['green', 'blue', 'red']);
console.log(colors.size); // 3
So far we've seen different ways to iterate the sets. Let's see all together once.
Different ways to iterate sets
// All these iterations return the same result
const cities = new Set(['Tokyo', 'Seoul', 'Rio', 'Delhi']);
for (const city of cities) console.log(city);
for (const city of cities.keys()) console.log(city);
for (const city of cities.values()) console.log(city);
for (const [key, value] of cities.entries()) console.log(key);
cities.forEach((c) => console.log(c));
// Converting javascript set to array
Array.from(cities).forEach((c) => console.log(c);
// Each iteration logs: Tokyo, Seoul, Rio, Delhi
When and where to use JS set?
A set is a collection of unique unordered elements and the elements can be iterated in the order of their insertion.
A set can be used
1. To remove the duplicates in an array
const letters = ['a', 'b', 'c', 'b', 'a', 'd']; // An array with duplicate letters
const uniqueLetters = [...new Set(letters)]; // Spreading the set created from the letters array
console.log(uniqueLetters);
// Logs: ["a", "b", "c", "d"]
2. To find if an element exists in an array effectively
Finding the existence of an element in an array of very large size may have performance problems. In such a case, set.has()
method could be handy. set.has()
has a time complexity of O(1) but it seems to be not guaranteed in all the situations. Learn more about it here.
set.has()
method works very effectively compared to array methods for checking the existence of an element in a large array.
const letters = ['a', 'b', 'c', ..., 'z']; // say a very large array
// indexOf() and findIndex() may have performance issues
letters.indexOf('z'); // letters.length - 1
letters.findIndex(l => l === 'z'); // letters.length - 1
// Converting to a set and finding the existence
const letterSet = new Set(letters);
console.log(letterSet.has('z')); // true
There's a special case of JS sets called WeakSet, let's have a glimpse at it.
What is a weak set in Javascript?
A weakset is similar to a set in Javascript but with limitations on the data types it can store and the methods it can have.
Unlike set, weakset can contain only the objects. And only add()
, has()
, delete()
methods are available on a WeakSet
instance. No iterative methods can be applied on weak sets, can't even check the size of a weakset.
const colors = new WeakSet();
const green = { name: 'green' };
const red = { name: 'red' };
colors.add(green);
colors.add(red);
colors.has(green); // true
colors.delete(red);
colors.has('red'); // false
// Try adding a string or any other data type except object to the weakset
colors.add('violet'); // Throws an error
A weakset is called so because of the weak references to the data(objects) it contains. When the reference to the objects is lost, they get garbage collected.
let a = { index: 1 };
let b = { index: 2 };
const wSet = new WeakSet();
wSet.add(a);
wSet.add(b);
console.log(wSet.has(a)); // true
console.log(wSet.has(b)); // true
a = null; // removing the reference for { index: 1 }
console.log(wSet.has(a)); // false
WeakSet is mainly used as additional storage of data for objects that are stored or managed from another location.
That was a quick look at weaksets and overall the sets in Javascript.