`Set` object
This article explains the Set object.
We will explain the Set object with practical examples.
YouTube Video
Set object
Set is a built-in object used to handle collections of unique, non-duplicate values. It allows you to write duplicate elimination and existence checks more simply than with arrays, and makes set operations like union and intersection easier to implement.
Basics: Creating and Using Sets
First, let's look at how to create a Set, add and remove elements, check for existence, and get its size.
Below is a basic pattern that creates a new Set and demonstrates add, has, delete, and size.
1// Create a Set and demonstrate add, has, delete, and size
2const s = new Set();
3
4s.add(1);
5s.add(2);
6s.add(2); // duplicate, ignored
7
8console.log(s.has(1)); // true
9console.log(s.has(3)); // false
10
11s.delete(2);
12console.log(s.size); // 1
13
14console.log([...s]); // [1]
- As shown in this code,
Setautomatically removes duplicate primitive values, and you can get the number of elements usingsize.
Iteration methods
Set is iterable, so you can loop over it using for...of or forEach. The order is the order of insertion.
Here are typical ways to use for...of and forEach.
1// Iterate a Set with for...of and forEach
2const s = new Set(['a', 'b', 'c']);
3
4for (const v of s) {
5 console.log('for...of:', v);
6}
7
8s.forEach((value, sameValue, setRef) => {
9 // Note: second arg is same as first for Set API to match Map signature
10 console.log('forEach:', value);
11});- The callback signature for
forEachisvalue, value, set(for compatibility with Map), but in practice, you usually only need the firstvalueargument.
Conversion between Arrays and Sets (useful for removing duplicates)
Here we show a simple technique for removing duplicates from an array, and how to convert a Set back to an array.
Below is an example of removing duplicates from an array by passing it through a Set.
1// Deduplicate an array using Set
2const arr = [1, 2, 2, 3, 3, 3];
3const deduped = [...new Set(arr)];
4console.log(deduped); // [1, 2, 3]
5
6// Convert a Set to an array using Array.from
7const s = new Set([4, 5, 6]);
8const arrFromSet = Array.from(s);
9console.log(arrFromSet); // [4, 5, 6]
- This pattern is short and fast, so it is frequently used for removing array duplicates. It is especially effective for primitive values.
Objects and Reference Handling
Objects in a Set are compared by reference, so different instances with the same content are treated as separate elements.
The following code demonstrates what happens when you add objects to a Set.
1// Objects are compared by reference in a Set
2const obj1 = { x: 1 };
3const obj2 = { x: 1 };
4
5const s = new Set();
6s.add(obj1);
7s.add(obj2);
8
9console.log(s.size); // 2 (different references)
10console.log(s.has(obj1)); // true
11console.log(s.has({ x: 1 })); // false (different object)
- Duplicate detection for objects is based on reference identity, so if you want to deduplicate based on object content alone, you will need to serialize or otherwise process them.
Special Values: Handling of NaN and -0/+0
Set uses the Same-value-zero comparison rule to determine value equality. This method of comparison has the following features regarding numbers:.
NaNis considered equal toNaN.- Positive
+0and negative-0are not distinguished and are treated as the same value.
Therefore, when you add these values to a Set, the following behavior occurs:.
1// NaN and zero behavior in Set
2const s = new Set();
3
4s.add(NaN);
5s.add(NaN);
6console.log(s.size); // 1 (NaN considered the same)
7
8s.add(+0);
9s.add(-0);
10console.log(s.size); // still 2 (NaN + 0)
11console.log([...s]); // [NaN, 0] (order may vary but only one zero)
- In normal comparison (
NaN === NaN), it returnsfalse, but inside aSet, allNaNvalues are considered 'the same value'. - +0 and -0 can be distinguished mathematically, but in a
Set, they are simply treated as0. - As a result, only one
NaNand one0remain in theSet. - The comparison rule of
Setis similar toObject.is, but not exactly the same.Object.is(+0, -0)returnsfalse, but in aSet, they are considered identical. Please take note of this difference.
Common Utility: Set Operations (Union, Intersection, Difference)
Set operations can be written more clearly using Set. Below are common implementation examples.
Here are examples of functions for union, intersection, and difference.
1// Set operations: union, intersection, difference
2function union(a, b) {
3 return new Set([...a, ...b]);
4}
5
6function intersection(a, b) {
7 return new Set([...a].filter(x => b.has(x)));
8}
9
10function difference(a, b) {
11 return new Set([...a].filter(x => !b.has(x)));
12}
13
14// Demo
15const A = new Set([1, 2, 3]);
16const B = new Set([3, 4, 5]);
17
18console.log('union', [...union(A, B)]); // [1,2,3,4,5]
19console.log('intersection', [...intersection(A, B)]); // [3]
20console.log('difference A\\B', [...difference(A, B)]); // [1,2]
- Set operations can be written simply by using filters with the combination of
Setand arrays. When dealing with large datasets, the O(1) performance ofhasmakes operations faster.
Practical Example: Finding Array Differences (Detecting Added/Removed Items)
The following example demonstrates how to use a Set to find the difference between two arrays (an old list and a new list). This allows you to identify which elements were added and which were removed.
1// Find added and removed items between two arrays
2function diffArrays(oldArr, newArr) {
3 const oldSet = new Set(oldArr);
4 const newSet = new Set(newArr);
5
6 const added = [...newSet].filter(x => !oldSet.has(x));
7 const removed = [...oldSet].filter(x => !newSet.has(x));
8
9 return { added, removed };
10}
11
12const oldList = [1, 2, 3];
13const newList = [2, 3, 4, 5];
14
15console.log(diffArrays(oldList, newList));
16// { added: [4,5], removed: [1] }
- This method is very convenient for detecting differences in ID lists, tag lists, and similar situations. It is simplest to use with primitive values.
Differences Between WeakSet and Set (Memory Management)
WeakSet is similar to Set, but it uses weak references, allowing its items to be garbage collected. The following demonstrates basic usages of WeakSet.
1// WeakSet basics (objects only, not iterable)
2const ws = new WeakSet();
3let obj = { id: 1 };
4ws.add(obj);
5
6console.log(ws.has(obj)); // true
7
8obj = null; // Now the object is eligible for GC; WeakSet won't prevent collection
WeakSet can only hold objects and cannot be iterated over. Below are examples of the constraints of WeakSet—it only holds objects, and cannot be iterated.
1// WeakSet basics (objects only, not iterable)
2const ws = new WeakSet();
3
4// --- Only objects can be added ---
5try {
6 ws.add(1); // number
7} catch (e) {
8 console.log("Error: WeakSet can only store objects. Adding a number is not allowed.");
9}
10
11try {
12 ws.add("text"); // string
13} catch (e) {
14 console.log("Error: WeakSet can only store objects. Adding a string is not allowed.");
15}
16
17// --- WeakSet is not iterable ---
18try {
19 for (const value of ws) {
20 console.log(value);
21 }
22} catch (e) {
23 console.log("Error: WeakSet is not iterable. You cannot use for...of to loop over its elements.");
24}
25
26// --- Cannot convert to array ---
27try {
28 console.log([...ws]);
29} catch (e) {
30 console.log("Error: WeakSet cannot be converted to an array because it does not support iteration.");
31}
32
33// The object becomes eligible for garbage collection
34let obj = { id: 1 };
35ws.add(obj);
36obj = null;WeakSetis useful for temporarily tracking the presence of objects, but you cannot enumerate its elements or get its size.
Performance and Choosing When to Use
When deciding whether to use a Set, it is important to understand its performance characteristics and the nature of your data.
has,add, anddeletetypically operate at nearly O(1) performance on average. Therefore, in scenarios where you frequently check for existence or remove duplicates,Setis often more advantageous than arrays.- Be careful if you want to deduplicate objects based on their contents (values). Since
Setcompares by reference, a practical way is to use IDs or other keys, or serialize objects into primitive values before using Sets when value-based comparison is needed. Setis particularly useful for improving code readability for small to medium-sized collections. On the other hand, if you're handling a very large number of elements or frequently converting between arrays and Sets, it is recommended to actually benchmark and test.
Common Pitfalls
Set is convenient, but if you are not aware of its specifications, you may be puzzled by unexpected behaviors. Here are some typical points to watch out for:.
- Objects are compared by reference, so even if their content is the same, different objects are not considered duplicates.
Setmaintains insertion order, but you cannot access elements by index like arrays. If you want to use index-based access, convert theSetto an array first.WeakSetcannot be enumerated, and can only store objects. Note that its applications are limited.NaNis treated as the same value, and+0and-0are not distinguished. This is due to the Same-value-zero comparison rule.
Summary
Set is a convenient data structure that allows you to handle collections of unique values intuitively. You can use it to remove duplicates from arrays, perform fast existence checks, or implement set operations like union and intersection with simple and readable code.
On the other hand, since objects are compared by reference, extra measures are needed if you want to judge equality based on their contents.
By understanding these characteristics and using them appropriately, Set becomes a powerful choice for improving code readability and maintainability.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.