Set.prototype.difference()
Returns a new collection of the values in this one that are absent from another set-like object.
difference(other)- Added in JavaScript ES2025
Parameters
| Parameter | Type | Description |
|---|---|---|
$other | Set | set-like object | A Set, or any set-like object: one exposing a numeric size property, a has() method taking an element and returning a boolean, and a keys() method returning an iterator of the elements. |
Return value
SetA new Set containing the elements of this set that are not in other, in this set's insertion order.
Errors
Throws a TypeError if other is not set-like (a plain array is not), or if called on a value that is not a real Set instance.
Changelog
- PHP ES2025Added along with union(), intersection(), symmetricDifference() and the subset/superset predicates; Baseline newly available since June 2024, so older engines need a polyfill.
difference() is A \ B: everything in this collection that other does not contain. Both operands are left untouched, and the result keeps this collection's insertion order — unlike intersection(), whose ordering depends on relative sizes.
It is not symmetric. a.difference(b) and b.difference(a) answer different questions, and neither is the same as symmetricDifference(), which returns the values in exactly one of the two. Getting the operands backwards is the most common mistake here, and it fails silently — you just get the wrong list.
Where it earns its place
Diffing two snapshots. Given a collection of ids before and after, after.difference(before) is the additions and before.difference(after) is the removals. That pair of calls replaces a hand-written double loop, and reads as what it means.
It also works as a non-mutating bulk delete: where delete() removes one value from the existing object, difference() produces a new collection with a whole group excluded, leaving the original intact for anything else holding a reference to it.
As with the other ES2025 methods, other must be set-like — an array throws.
Example
When to use it
- Diff before and after id snapshots into additions and removals
- Strip every block-listed tag from a selection without mutating it
- Report which required fields a submitted payload is still missing
- Remove a group of values non-destructively where delete() would mutate
Frequently asked questions
What is the difference between difference() and symmetricDifference()?
difference() returns only what this collection has and the other lacks, while symmetricDifference() returns what is in exactly one of the two, in either direction. The first is directional; the second is not.
Does difference() remove elements from the original Set?
No. It returns a new collection and leaves both operands unchanged, which makes it the non-mutating alternative to looping over delete().
Why does difference() reject an array argument?
Because the argument must be set-like — it needs a numeric size, a has() method and a keys() method, and an array has length instead. Wrap it: mySet.difference(new Set(arr)).
More examples
Diffing two snapshots
Reversing the operands turns the additions query into the removals query — added is [5], removed is [1, 2]. symmetricDifference() combines both sides into [1, 2, 5], which is the union of the two differences.
const before = new Set([1, 2, 3, 4]);
const after = new Set([3, 4, 5]);
console.log("added:", [...after.difference(before)]);
console.log("removed:", [...before.difference(after)]);
console.log("kept:", [...before.intersection(after)]);
console.log("changed either way:", [...before.symmetricDifference(after)]);Non-mutating bulk removal
difference() produces a filtered copy while the original selection still holds all four values, which matters when other code shares that reference. The delete() loop below achieves the same contents by destroying the original.
const selection = new Set(["a", "b", "c", "d"]);
const blocked = new Set(["b", "d"]);
const visible = selection.difference(blocked);
console.log([...visible]);
console.log([...selection]);
// The mutating equivalent
for (const v of blocked) selection.delete(v);
console.log([...selection]);Reporting missing required fields
One pair of calls in opposite directions covers both validation questions: email is missing, extra is unexpected. Order in the missing list follows required, so the message matches the order the fields are documented in.
const required = new Set(["name", "email", "country"]);
const payload = { name: "ada", country: "UK", extra: 1 };
const provided = new Set(Object.keys(payload));
const missing = required.difference(provided);
const unexpected = provided.difference(required);
console.log("missing:", [...missing], missing.size);
console.log("unexpected:", [...unexpected]);
console.log("valid?", missing.size === 0);
Discussion