📌 JavaScript

What is a JavaScript Set? When and where to use JS sets?

December 31, 2021

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();
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 set
  • has() - to check if the set has a particular element
  • delete() - to delete the element if it exists
  • clear() - to clear/delete all the elements of the set
  • values() - to get the iterator of values inside the set
  • keys() - same as values(). It is there just to match the methods with the map data type
  • entries() - 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 type
  • forEach() - to call/invoke a callback function on every element in a set
  • size - 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
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) {
// 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
console.log(colors.size); // 2

clear() method

const colors = new Set(['green', 'blue', 'red']);

// Clears or deletes all the elements in a set
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()) {
// Logs: green, blue, red

for(const color of colors.keys()) {
// 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 but set.entries() returns an iterator with [key, value] arrays.

const colors = new Set(['green', 'blue', 'red']);

for(const color of colors.entries()) {
// 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
// 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.has(green); // true
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();

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.

If you like receiving regular tips, tricks related to web development and technology then do follow on devapt-twitter @dev_apt