JavaScript Set and WeakSet

JavaScript Set and WeakSet

Photo by Ross Joyner on Unsplash

In JavaScript, a set is an object that allows you to store unique values of any type. It is a collection of values where each value occurs only once.

The Set object is used to store and retrieve values, and it provides a range of methods to manipulate the set. Some commonly used methods include add(), has(), delete(), clear(), size(), and values().

Here's an example of how to create a set with some values:

let mySet = new Set([1, 2, 3, 4, "hello", true]);

// add a new value to the set
mySet.add(5);

// check if the set has a certain value
let hasHello = mySet.has("hello");

// remove a value from the set
mySet.delete(4);

// get the size of the set
let setSize = mySet.size;
console.log(setSize); // 6

// get all the values in the set
let setValues = mySet.values();
console.log(setValues); // [Set Iterator] { 1, 2, 3, 'hello', true, 5 }

Sets are useful for creating lists of unique items, and for performing calculations on data where duplicates are not needed or can cause errors. This example demonstrates how to use a set to find duplicates in an array:

const arr = [1, 2, 3, 4, 5, 2, 4, "hello", "world", "hello"];

const findDuplicates = arr => {
  let set = new Set();
  let duplicates = new Set();

  arr.forEach(item => {
    if (set.has(item)) {
      duplicates.add(item);
    }
    else {
      set.add(item);
    }
  });

  return Array.from(duplicates);
}

let duplicates = findDuplicates(arr);
console.log(duplicates); // [2, 4, "hello"]

In this example, we create a function called findDuplicates that accepts an array as an argument. We then create two sets, set and duplicates. We loop through the array and check if each item is already in the set. If it is, we add it to the duplicates set. If it's not, we add it to the set so we can check for duplicates. Finally, we convert the duplicates set to an array using the Array.from() method and return it.

When we run this code, we get an array of the items that appear more than once in the original array: [2, 4, "hello"].

Iterating sets

To iterate over a set, you can use either the for...of loop or the forEach() method. for example:

const set = new Set([1, 2, 3, 4, 5]);

for (let item of set) {
  console.log(item);
}

This will output each value of the set on a separate line in the console:

1
2
3
4
5

Basic set operations

You can use the set data structure to implement basic set operations:

const set1 = new Set([1, 2, 3, 4, 5]);
const set2 = new Set([4, 5, 6, 7, 8]);

// Union of sets
const union = new Set([...set1, ...set2]);
console.log(union); // Set [1, 2, 3, 4, 5, 6, 7, 8]

// Intersection of sets
const intersection = new Set([...set1].filter(x => set2.has(x)));
console.log(intersection); // Set [4, 5]

// Difference of sets
const difference = new Set([...set1].filter(x => !set2.has(x)));
console.log(difference); // Set [1, 2, 3]

In this example, we create two sets set1 and set2 with some values.

We then create a union set by using the spread operator to create a new set with all the values from both set1 and set2.

We create an intersection set by using the filter() method to loop through the values of set1, and checking if set2 has each value.

You can create a difference set by using the filter() method to loop through the values of set1 and checking if each value is not present in set2.

JavaScript WeakSet

In JavaScript, a WeakSet is a built-in object that allows you to store weakly held object references in a collection.

A WeakSet contains a group of objects, each of which can only be added to the set once, but the objects are held through weak references, which means that if no other reference to the object exists, it can be garbage collected. As a result, the WeakSet object is also itself weakly held. Unlike Set, WeakSet can only contain objects and not primitive values.

Here's an example of creating a WeakSet in JavaScript:

let obj1 = { name: 'John' };
let obj2 = { name: 'Jane' };
let obj3 = { name: 'Mike' };

let weakSet = new WeakSet();

weakSet.add(obj1);
weakSet.add(obj2);
weakSet.add(obj3);

console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj2)); // true
console.log(weakSet.has({ name: 'John' })); // false
console.log(weakSet.size); // undefined

In this example, we create three objects obj1, obj2, and obj3. We then create a WeakSet and add each object to it using the add() method.

We use the has() method to check if the set contains each object. Note that even though a new object with the same property values like ({ name: 'John' }) is created and it has the same "name" value as the obj1, it's not considered equal to the obj1 object and the has() method returns false.

The size property is not available for WeakSet, because of its weakly held nature it is not possible to iterate over it.

WeakSet use cases

Here are some common use cases for WeakSet:

  1. Garbage collection: When objects are no longer needed in JavaScript, they are usually marked for garbage collection. However, when objects are held in a regular Set, they cannot be garbage collected, even if they are not in use anymore. In contrast, when objects are added to a WeakSet, they can be garbage collected if they are no longer referenced by any other part of the program.

  2. Privacy and security: You can use WeakSet to store private keys or secret objects that should not be accessible from outside your code. Since WeakSet objects cannot be accessed from outside your code, they provide an extra layer of security for your sensitive data.

  3. Event subscriptions: You can use WeakSet to keep track of event subscriptions. When an event is no longer needed, you can simply remove it from the WeakSet, and the event listener will be automatically removed as well.

  4. Caching: You can use a WeakSet to cache objects that are expensive to create or obtain. When an object is requested, you can check if it exists in the WeakSet first, and if it does, you can return the cached version instead of creating a new one.

Overall, WeakSet is a useful tool to manage collections of objects that need to be garbage collected, need to be kept private, or need to be cached for performance reasons.