Set.prototype.difference()
difference(other) Syntax
Set.prototype.difference() is called on a Set instance and returns a new Set containing the elements that are present in the receiver but absent from the argument:
setInstance.difference(other)
Parameters
other— ASetinstance, or any set-like object exposing ahasmethod and asizeproperty. Arrays do not qualify on their own; wrap them innew Set(arr)first.
Return value
A new Set containing the elements that exist in the receiver and not in other. Neither input is modified.
Description
This is the JavaScript equivalent of mathematical set difference: A \ B = {x ∈ A | x ∉ B}. Membership uses SameValueZero, the same equality Set uses internally, so NaN equals NaN and +0 equals -0.
Two details follow from how the engine reads the receiver’s internal storage:
- The receiver must be a real
Set. Callingdifference()on a plain set-like throws aTypeError. - The argument is set-like-friendly. Any object with
hasandsizeworks.
The implementation picks the cheaper side. When other is smaller than this, the engine iterates other first (collecting keys to skip) and then streams this. Otherwise it walks this once and calls other.has(x) for each element. The returned Set preserves the insertion order of this.
Because the result is a fresh Set, calls chain naturally:
const a = new Set([1, 2, 3, 4]);
const b = new Set([2]);
const c = new Set([3]);
console.log(a.difference(b).difference(c));
// Set(2) { 1, 4 }
One gotcha: difference is not symmetric. a.difference(b) and b.difference(a) differ unless the sets are disjoint. For the symmetric version use Set.prototype.symmetricDifference(). Set difference is also not strictly associative, so when chaining, pay attention to which side each call operates on and which set ends up on the receiving end of the next subtraction.
Examples
Find elements in one set but not another
const odds = new Set([1, 3, 5, 7, 9]);
const squares = new Set([1, 4, 9]);
console.log(odds.difference(squares));
// Set(3) { 3, 5, 7 }
Pass a set-like argument
Any object that exposes has and size works as the second argument, which is useful when integrating with libraries that already maintain a custom collection:
const evens = {
size: 2,
has(x) { return x === 2 || x === 4; },
keys() { return [2, 4].values(); },
};
console.log(new Set([1, 2, 3, 4]).difference(evens));
// Set(2) { 1, 3 }
NaN matches and gets filtered
SameValueZero equality means NaN is treated as equal to NaN, so a NaN on the right removes the NaN on the left. This is different from how === compares the two values, but it matches the behavior of Set membership and Array.prototype.includes:
console.log(new Set([NaN, 1, 2]).difference(new Set([NaN])));
// Set(2) { 1, 2 }
Inputs are not mutated
difference() always allocates a fresh Set. Calling it has no side effects on either input, so it is safe to call inside reducers, render functions, or any other spot where you would otherwise have to clone the set first to avoid leaking state:
const x = new Set([1, 2, 3]);
const y = new Set([2]);
x.difference(y);
console.log(x);
// Set(3) { 1, 2, 3 }
console.log(y);
// Set(1) { 2 }
Set.prototype.difference() performance
Before ES2025, the idiomatic way to compute set difference in JavaScript was to spread the receiver into an array and filter out any element that the other set already contained:
const a = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const b = new Set([2, 4, 6, 8, 10]);
const result = new Set([...a].filter(x => !b.has(x)));
console.log(result);
// Set(5) { 1, 3, 5, 7, 9 }
Set.prototype.difference() does the same work without materialising an intermediate array. It also routes through whichever of the two sets is smaller, so handing it a small b and a large a is exactly the case it is tuned for, and the larger side never gets walked twice.
Browser support
Set.prototype.difference() is part of the new Set methods proposal by Michał Wadas, which graduated to Stage 4 in 2023 and ships with the ECMAScript 2025 specification. Support reached Baseline 2024 in June 2024:
| Engine | First version |
|---|---|
| Chrome / Edge | 122 (Feb 2024) |
| Firefox | 127 (Jun 2024) |
| Safari | 17.0 (Sep 2023) |
| Node.js | 22.0.0 |
For older environments, both core-js and es-shims provide a polyfill. core-js ships a broad collection-level patch, while es-shims offers a smaller, focused polyfill that covers the new Set methods individually and follows the spec closely.
Summary
Set.prototype.difference() is the cleanest way to compute A \ B in JavaScript. It is non-mutating, runs in linear time, preserves insertion order, and accepts any set-like object. Reach for it whenever you need to subtract one collection of unique values from another.