Articles

JavaScript Set Methods: Union, Intersection, Difference

JavaScript's Set object now has built-in union, intersection, difference, and subset methods — replacing manual loops for combining collections.

Takina Takina · · 3 min read
Dark-themed code editor showing JavaScript

JavaScript’s built-in Set object now ships native methods for combining and comparing sets — union(), intersection(), difference(), symmetricDifference(), and the boolean checks isSubsetOf(), isSupersetOf(), and isDisjointFrom(). Before these existed, every one of these operations meant converting sets to arrays, looping, and rebuilding a Set by hand. Now they’re one method call.

What a Set already gave you

A Set stores unique values with fast membership checks:

const a = new Set([1, 2, 3]);
a.has(2); // true
a.add(4);
a.size; // 4

That part hasn’t changed. What’s new is the vocabulary for combining two sets — operations borrowed directly from set theory in mathematics.

The new methods

const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);

a.union(b);              // Set {1, 2, 3, 4, 5, 6}
a.intersection(b);       // Set {3, 4}
a.difference(b);         // Set {1, 2}        (in a, not in b)
b.difference(a);         // Set {5, 6}        (in b, not in a)
a.symmetricDifference(b);// Set {1, 2, 5, 6}  (in exactly one)

And the boolean comparisons:

new Set([1, 2]).isSubsetOf(a);     // true  — every element of {1,2} is in a
a.isSupersetOf(new Set([1, 2]));   // true  — a contains every element of {1,2}
new Set([9]).isDisjointFrom(a);    // true  — no elements in common

Every method accepts any set-like object — not just a Set instance — as long as it exposes a size property and has()/keys() methods, which is enough for these to interoperate with custom collection classes.

Before: the manual version

This is the pattern these methods replace:

// intersection, the old way
const intersection = new Set([...a].filter((x) => b.has(x)));

// union, the old way
const union = new Set([...a, ...b]);

// difference, the old way
const difference = new Set([...a].filter((x) => !b.has(x)));

Union was always reasonably concise via spread. Intersection and difference required a filter and a manual re-wrap into Set, and it was easy to get the order backwards (a.filter(x => b.has(x)) vs b.filter(x => a.has(x)) — these are not the same operation for difference). The named methods remove that ambiguity entirely: a.difference(b) unambiguously means “in a, not in b.”

Where this actually comes up

Set operations show up constantly in UI state, not just algorithms homework:

  • Permission checks. userRoles.isSupersetOf(requiredRoles) reads more directly than a manual every() loop over an array.
  • Diffing selections. In a multi-select UI, newSelection.symmetricDifference(oldSelection) gives you exactly the items that were added or removed — useful for firing minimal update events instead of re-rendering everything.
  • Tag filtering. postTags.intersection(activeFilters).size > 0 is a clean way to check whether a post matches any active filter tag.
  • Deduplicating across sources. union() across sets pulled from multiple API responses collapses duplicates in one line, without the array-spread-then-new Set() dance.

A note on mutation

None of these methods mutate the receiver — a.union(b) returns a new Set and leaves a and b untouched, consistent with how Array.prototype.map and filter behave rather than how Array.prototype.sort used to. If you’re coming from Object.freeze habits or immutable-data patterns elsewhere in your codebase, these methods fit right in.

Feature support

Because this is a relatively recent JavaScript addition, check your target runtime’s support before relying on it in code that needs to run in older browsers or Node versions — Node’s release notes and the usual browser compatibility tables are the place to verify, rather than assuming. If you need to support older environments, a small polyfill or the manual filter-based patterns above cover the gap without changing behavior.

The takeaway

Set.prototype.union, intersection, difference, symmetricDifference, and the three isSubsetOf/isSupersetOf/isDisjointFrom checks turn a handful of filter-and-Set-rebuild idioms into single, unambiguous method calls. They don’t mutate their receiver, they accept any set-like object, and they read closer to the actual intent — reach for them anywhere you’re currently spreading two collections into arrays just to compare or combine them.

Takina Takina · · 4 min read

Svelte 5 Runes Explained

Svelte 5 runes like $state and $derived replace the old reactive-assignment magic with explicit function calls that work anywhere in a file.

#JavaScript #Frameworks #Web Development
Takina Takina · · 4 min read

Shallow Copy vs Deep Copy in JavaScript

A shallow copy duplicates an object's top-level properties but shares nested references; a deep copy duplicates everything recursively. How to do each.

#JavaScript #Web Development #Frontend