JavaScript Set Methods: union, intersection, difference in ES2025

ES2025 finalises a long-awaited addition to the Set prototype: seven new methods — union(), intersection(), difference(), symmetricDifference(), isSubsetOf(), isSupersetOf(), and isDisjointFrom(). All are available in Chrome 122+, Firefox 127+, and Safari 17+ without any polyfill. They replace verbose reduce/filter patterns and work on any Set-like object (anything with size, has(), and keys()).

Problem: JavaScript code that computes unions, intersections, and differences between sets of post IDs, user capabilities, or tag arrays uses manual filter() + has() patterns that are verbose and easy to get wrong.

Solution: Use the native JavaScript Set Methods (ES2025): a.union(b), a.intersection(b), a.difference(b), a.symmetricDifference(b), and a.isSubsetOf(b). All methods are available in Chrome 122+, Firefox 127+, and Safari 17+, and return new Set instances without mutating the originals.


The examples below demonstrate all seven methods and show a practical use case: comparing two sets of WordPress post tags to find shared, unique, and removed tags during a bulk-edit operation.


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

// ── New Set methods ──────────────────────────────────────────────────────
a.union( b )               // Set {1,2,3,4,5,6}  — all elements from both
a.intersection( b )        // Set {3,4}           — only elements in both
a.difference( b )          // Set {1,2}           — in a but not in b
a.symmetricDifference( b ) // Set {1,2,5,6}       — in either but not both

a.isSubsetOf( b )          // false
a.isSupersetOf( new Set([1,2]) ) // true
a.isDisjointFrom( new Set([7,8]) ) // true  — no shared elements

// ── Practical example: WordPress tag diff during bulk edit ───────────────
const originalTags = new Set( ['javascript', 'php', 'wordpress', 'css'] );
const updatedTags  = new Set( ['javascript', 'wordpress', 'gutenberg', 'react'] );

const added   = updatedTags.difference( originalTags );
// Set {'gutenberg', 'react'}  — new tags to add

const removed = originalTags.difference( updatedTags );
// Set {'php', 'css'}          — tags to detach

const kept    = originalTags.intersection( updatedTags );
// Set {'javascript', 'wordpress'} — unchanged tags

console.log( 'Added:', [...added] );
console.log( 'Removed:', [...removed] );
console.log( 'Kept:', [...kept] );

// ── Works on Set-like objects too (e.g. a Map's keys()) ──────────────────
const mapA = new Map( [['a',1],['b',2],['c',3]] );
const setB  = new Set( ['b','c','d'] );

// Map's keys() is Set-like: has .size, .has(), .keys()
// So we can pass it directly:
new Set( mapA.keys() ).intersection( setB ); // Set {'b','c'}


NOTE: The new methods return new Set instances and never mutate the original — they are pure functions; if you need in-place mutation (e.g., to avoid allocation in a hot loop), you still need to iterate and call add()/delete() manually.