jsguides

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 — A Set instance, or any set-like object exposing a has method and a size property. Arrays do not qualify on their own; wrap them in new 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. Calling difference() on a plain set-like throws a TypeError.
  • The argument is set-like-friendly. Any object with has and size works.

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:

EngineFirst version
Chrome / Edge122 (Feb 2024)
Firefox127 (Jun 2024)
Safari17.0 (Sep 2023)
Node.js22.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.

See also