cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Set operations

Use the ES2025 Set methods for union, intersection, difference, relationship checks, and set-like inputs without mutating your original data.

By the end you can
  • 01
    Combine unique values clearlyUse union, intersection, difference, and symmetricDifference instead of hand-written array filters.
  • 02
    Ask relationship questionsCheck subsets, supersets, and disjoint sets for permissions, tags, and matching features.
  • 03
    Recognize set-like inputsKnow why Maps work, custom set-like objects work, and arrays must be wrapped in new Set().

Sets as friend groups

A Set already gives you uniqueness: a value can appear once, no matter how many times you try to add it. ES2025 adds the missing vocabulary for comparing two Sets: union, intersection, difference, symmetric difference, and three true/false relationship checks.

The curriculum summary for this lesson is simple: union, intersection, and difference with the built-in Set methods. The important upgrade is clarity. Instead of translating a question into spreads, filter, and includes, you can write the question you mean.

Real-life analogyTwo friend groups at a party

Imagine two friend groups arriving at a party. You can ask, “Who is in either group?”, “Who is in both?”, “Who is only with us?”, or “Who is not shared?” Those are set operations. The new methods make the questions read like English.

In real life: Everyone either group invited
In JavaScript: a.union(b)
In real life: Friends both groups know
In JavaScript: a.intersection(b)
In real life: People only my group knows
In JavaScript: a.difference(b)
In real life: Everyone except the shared friends
In JavaScript: a.symmetricDifference(b)

Where the analogy stops: Friend groups are fuzzy in real life. JavaScript Sets are exact: membership is tested with the same equality rules Set already uses, so objects only match when they are the same object reference.

Availability note

These are ES2025 methods, available in Node 22 and modern browsers. The playground below feature-detects them after the page mounts. If a browser does not support them yet, use a manual fallback with arrays and filter/includes, or a vetted polyfill.

This lesson builds on Map & Set for Set basics, on Searching arrays for the old filter/includes style, and on map/filter/reduce for list transformations.

Union & intersection

INTERACTIVE

a.union(b) creates a new Set containing values from a, then values from b that are not already present. That order rule matters when you turn the result back into an array: the caller’s insertion order comes first, then the argument contributes only new values.

a.intersection(b) creates a new Set containing values that appear in both. For ordinary Sets of the same size, you can think “walk the left Set and keep matches.” The specification may iterate the smaller side for efficiency, but the lesson examples use small Sets where the visible result is stable and tested.

Live Venn diagram playground
Native Set operationPop out in the code editor (opens in a new tab)JavaScript
const devA = new Set(["JavaScript","CSS","Accessibility"]);const devB = new Set(["CSS","React","Testing"]);const result = [...devA.union(devB)];console.log(result);

Developer A

Developer B

Diagramunion
A onlyJavaScript, Accessibility
BothCSS
B onlyReact, Testing
Result Set[JavaScript, CSS, Accessibility, React, Testing]
Original A[JavaScript, CSS, Accessibility]
Original B[CSS, React, Testing]
Try it yourself

Checking this browser after mount so the server and browser render the same page.

Toggle chips for two developers' skill Sets. The diagram is conceptual, but every result is computed by the native Set method in the visible code.

The Venn diagram is labeled as a diagram because JavaScript is not drawing circles internally. The result list beside it is real: it comes from the native method shown in the code pane. Notice that the original Sets stay unchanged after every operation.

Step through the four result-making methods
Step 0 of 6Ready
Your turn: follow the blue line

Step through four operations. Each result is a real Set produced by the native ES2025 methods.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const yourFriends = new Set(["Bea", "Cal", "Dev"]);myFriends.union(yourFriends);myFriends.intersection(yourFriends);myFriends.difference(yourFriends);myFriends.symmetricDifference(yourFriends);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Difference & symmetricDifference

STEP THROUGH

difference is directional. oldTags.difference(newTags) means “what was removed?” newTags.difference(oldTags) means “what was added?” Same two Sets, different caller, different question.

symmetricDifference is the “changed on either side” operation: values that appear in exactly one Set. It is great for summaries, but less precise than running difference both ways when you need separate added and removed lists.

Swap the caller
Step 0 of 5Ready
Your turn: follow the blue line

Use the setting to swap which Set calls the method. Difference is the easiest place to see why direction matters.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const newTags = new Set(["js", "react", "accessibility"]);oldTags.difference(newTags);oldTags.isSupersetOf(newTags);oldTags.isDisjointFrom(newTags);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Which Set calls the method?

Changing the caller starts a fresh replay. Watch line 3: it answers a different question.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Real-life analogyA checklist before and after a trip

Compare what was in your backpack before and after a trip. The direction tells you whether you lost something or added something. If you only care that the packing list changed, symmetric difference gives one combined list.

In real life: Packed before but not after
In JavaScript: before.difference(after) finds removed items
In real life: Packed after but not before
In JavaScript: after.difference(before) finds added items
In real life: Changed either way
In JavaScript: before.symmetricDifference(after)

Where the analogy stops: A backpack can have two identical socks. A Set cannot store duplicates, so these methods answer membership questions, not quantity questions.

isSubsetOf, isSupersetOf & isDisjointFrom

The three predicate methods return booleans. Use them when the answer should be true or false, not a new collection.

  • small.isSubsetOf(big): every value in small is also in big.
  • big.isSupersetOf(small): big contains every value from small.
  • a.isDisjointFrom(b): the Sets share no values at all.
Real-life analogyBook club inside the school roster

A book club can be fully inside a school roster. That same fact can be said from either side: the club is a subset of the school, and the school is a superset of the club. Two sports teams are disjoint only if no student appears on both rosters.

In real life: Every book club member attends the school
In JavaScript: bookClub.isSubsetOf(school)
In real life: The school contains the whole book club
In JavaScript: school.isSupersetOf(bookClub)
In real life: Two teams share nobody
In JavaScript: teamA.isDisjointFrom(teamB)

Where the analogy stops: The method only checks membership. It does not explain which value made the answer false; use difference when you need that report.

Permissions checkPop out in the code editor (opens in a new tab)JavaScript
const required = new Set(["read", "write"]);
const user = new Set(["read", "write", "delete"]);

if (required.isSubsetOf(user)) {
  console.log("allowed");
}

The caller communicates intent. “Are all required permissions inside the user’s permissions?” reads clearly as required.isSubsetOf(user). The equivalent user.isSupersetOf(required) is also correct; choose the one that matches your sentence.

Set-like objects

STEP THROUGH

The argument to these methods does not have to be an actual Set. It must be set-like: an object with a numeric size, a has(value) method, and a keys() method that produces its values. A Map qualifies because its keys act like the set of values.

Map, custom set-like, and array mistake
Step 0 of 6Ready
Your turn: follow the blue line

Set methods accept set-like objects, not every iterable. Step through a Map, a custom object, and an array mistake.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const requiredMap = new Map([["read", true], ["write", true]]);userPermissions.isSupersetOf(requiredMap);const requiredLike = {  size: 2,  has(value) { return value === "read" || value === "write"; },  keys() { return ["read", "write"][Symbol.iterator](); },};userPermissions.isSupersetOf(requiredLike);userPermissions.union(["read"]);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Set-like sourcePop out in the code editor (opens in a new tab)JavaScript
const userPermissions = new Set(["read", "write", "admin"]);const requiredMap = new Map([["read", true], ["write", true]]);userPermissions.isSupersetOf(requiredMap);const requiredLike = {  size: 2,  has(value) { return value === "read" || value === "write"; },  keys() { return ["read", "write"][Symbol.iterator](); },};userPermissions.isSupersetOf(requiredLike);userPermissions.union(["read"]);

Arrays are iterable, but they are not set-like because arrays do not have has(value). Passing an array throws a TypeError. Write mySet.union(new Set(array)) when your data starts as an array.

The old way vs the new way

Before these methods, you already had the tools: spread a Set into an array, filter the other array, and check membership with has or includes. That still works and is the right fallback when you cannot rely on ES2025 support. The new methods are easier to read and harder to get subtly wrong.

Same union, two stylesPop out in the code editor (opens in a new tab)JavaScript
const a = new Set(["js", "css", "html"]);const b = new Set(["css", "react"]);const newWay = [...a.union(b)];const oldWay = [...a, ...[...b].filter((item) => !a.has(item))];console.log(newWay.join(", "));console.log(oldWay.join(", "));console.log([...a].join(", "));

Both styles print the same union, and line 7 proves the original caller is still js, css, html. These methods return new Sets; they do not mutate the originals.

Set operation reference
MethodReturnsVenn regionExample result
a.union(b)A new SetEverything in either circle['Ada', 'Bea', 'Cal', 'Dev']
a.intersection(b)A new SetOnly the overlap['Bea', 'Cal']
a.difference(b)A new SetOnly the left circle['Ada']
a.symmetricDifference(b)A new SetBoth outside-only regions['Ada', 'Dev']
a.isSubsetOf(b)BooleanIs the left circle fully inside the right?false
a.isSupersetOf(b)BooleanDoes the left circle contain the right?false
a.isDisjointFrom(b)BooleanDo the circles never overlap?false
Which operation answers this?
  • Everyone invited by either friend group
  • People both groups already know
  • Tags that were removed from the old list
  • Tags that appear on exactly one side
  • Does this user have every required permission?
  • Do these two teams share nobody?
  • People only my friend group knows
  • Does the school roster contain the whole book club?
Try it yourself
0 of 8 correct

Sort each real question by the kind of Set operation it needs. Directional cards are the ones where swapping caller and argument changes the meaning.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Where you'll use this

Set operations show up whenever lists represent membership: tags, permissions, selected filters, feature flags, shopping-list ingredients, or shared interests.

Added and removed tagsPop out in the code editor (opens in a new tab)JavaScript
const before = new Set(["js", "css", "accessibility"]);
const after = new Set(["js", "react", "accessibility"]);

const added = after.difference(before);   // Set { "react" }
const removed = before.difference(after); // Set { "css" }
const changed = before.symmetricDifference(after); // Set { "css", "react" }
Common interestsPop out in the code editor (opens in a new tab)JavaScript
const mia = new Set(["music", "hiking", "games"]);
const noor = new Set(["cooking", "music", "games"]);

const shared = mia.intersection(noor); // Set { "music", "games" }

A good habit: keep your domain sentence beside the code. “Added tags” is after.difference(before); “removed tags” is before.difference(after). That sentence prevents swapped arguments during maintenance.

Common misconceptions

“Union changes the first Set.”

No. union, intersection, difference, and symmetricDifference return new Sets.

“Difference works the same both ways.”

No. a.difference(b) means values only in a. Swap the caller and you ask a different question.

“Arrays count as set-like because they are iterable.”

No. Set-like means size, has, and keys. Wrap arrays in new Set(array).

“Intersection always reports in the caller’s order.”

Often in small examples, yes, but the spec can use the smaller collection for efficiency. Do not rely on intersection as a sorting tool.

“Set equality is deep equality.”

Objects match only when they are the same object reference. Two separate { id: 1 } objects are different Set values.

Professional habit

If you want to keep a result, name it: const added = after.difference(before). The original Sets are still available for other checks, which makes these methods friendly to immutable update patterns.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict union and intersection

Predict the two printed lines.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const a = new Set(["red", "blue", "green"]);
const b = new Set(["blue", "gold"]);
console.log([...a.union(b)].join(", "));
console.log([...a.intersection(b)].join(", "));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeCheck required permissions

    Does the user have every required permission?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const required = new Set(["read", "write"]);
    const user = new Set(["read", "write", "delete"]);
    console.log(required.isSubsetOf(user));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind added and removed tags

      Type the added tag and the removed tag.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const before = new Set(["js", "css", "accessibility"]);
      const after = new Set(["js", "react", "accessibility"]);
      console.log([...after.difference(before)].join(", "));
      console.log([...before.difference(after)].join(", "));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeFix passing an array to union

        The starter code passes an array to union. Fix it by wrapping the array, then predict the output.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const favorites = new Set(["tea", "coffee"]);
        const incoming = ["coffee", "juice"];
        console.log([...favorites.union(incoming)].join(", "));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeCompute shared ingredients

          Which recipe ingredients are already in the pantry?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const pantry = new Set(["flour", "eggs", "milk", "sugar"]);
          const recipe = new Set(["eggs", "butter", "sugar"]);
          console.log([...pantry.intersection(recipe)].join(", "));

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS
            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does union return?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the difference snippet print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const a = new Set(["a", "b", "c"]);
              const b = new Set(["b", "d"]);
              console.log([...a.difference(b)].join(""));

              Choose an answer to see the explanation.

            3. Question 3 of 7Which method answers: does the user have every required permission?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does the subset snippet print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const school = new Set(["Mina", "Omar", "Pia"]);
              const bookClub = new Set(["Mina", "Pia"]);
              console.log(bookClub.isSubsetOf(school));

              Choose an answer to see the explanation.

            5. Question 5 of 7Which argument is set-like for these Set methods?

              Choose an answer to see the explanation.

            6. Question 6 of 7What does the symmetric difference snippet print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const a = new Set(["JS", "CSS"]);
              const b = new Set(["CSS", "HTML"]);
              console.log([...a.symmetricDifference(b)].join(","));

              Choose an answer to see the explanation.

            7. Question 7 of 7Do these methods mutate the original Sets?

              Choose an answer to see the explanation.

            Key takeaways

            • union, intersection, difference, and symmetricDifference return new Sets.
            • difference is directional; swap the caller to answer the opposite side.
            • isSubsetOf, isSupersetOf, and isDisjointFrom return booleans.
            • Set-like arguments need size, has, and keys. Maps work; arrays must be wrapped in new Set(array).
            • Feature-detect in browsers that may not have ES2025 Set methods yet.

            Remember the one-liner.
            Set operations let Sets answer membership questions directly: combine, compare, or ask relationships without mutating the originals.

            Up next: WeakMap & WeakSet.

            CompleteFrontend Clear concepts. Working examples.