Modern JS & AsyncExtra· 45 min read

Modern Operators: Rest, Optional Chaining, Nullish & Map/Set

A handful of small modern operators that make everyday code safer and shorter — and two new collections beyond arrays and objects.

What you will learn

  • Collect leftovers with the rest pattern
  • Read deep data safely with ?. and ??
  • Use Map and Set for lookups and de-duplicating

Rest — collect the leftovers

You saw the spread ... earlier (it spreads items out). The same three dots used on the left side does the opposite: it gathers several values into one array or object. That gathering use is called the rest pattern.

A common use is a function that accepts any number of arguments — you collect them all into one array.

Rest gathers all arguments into one array
<script>
  // ...numbers gathers every argument into an array called numbers
  function sumAll(...numbers) {
    return numbers.reduce((total, n) => total + n, 0);
  }
  document.write(sumAll(2, 4, 6) + "<br>");      // 12
  document.write(sumAll(10, 20, 30, 40));        // 100
</script>
Live preview

Inside sumAll, ...numbers scoops up every argument you pass into a real array. So sumAll(2, 4, 6) makes numbers equal to [2, 4, 6], and reduce adds them to 12. The next call passes four numbers and they are all gathered the same way — the function adapts to however many you give it.

Note: Output: 12 100

Rest also works when destructuring — grab the first item, gather the rest into an array:

First item out, the rest gathered
<script>
  const [winner, ...others] = ["Asha", "Ravi", "Maya", "Sam"];
  document.write("Winner: " + winner + "<br>");
  document.write("Runners-up: " + others.join(", "));
</script>
Live preview

winner takes the first item ("Asha") by position; then ...others sweeps up everything left into a new array ["Ravi", "Maya", "Sam"]. So one line splits a list into "the first" and "all the rest".

Note: Output: Winner: Asha Runners-up: Ravi, Maya, Sam

Optional chaining ?. — read deep data without crashing

Real data often has missing pieces. If you read user.address.city but address does not exist, JavaScript crashes with an error. The optional chaining operator ?. says "only keep going if this part exists; otherwise just give back undefined quietly".

Optional chaining ?. avoids "cannot read property" crashes
<script>
  const user1 = { name: "Asha", address: { city: "Bengaluru" } };
  const user2 = { name: "Ravi" };   // no address at all

  document.write(user1.address?.city + "<br>");   // Bengaluru
  document.write(user2.address?.city);            // undefined (no crash)
</script>
Live preview

For user1, address exists, so address?.city reads "Bengaluru" normally. For user2, there is no address — without ?. the line user2.address.city would throw "Cannot read properties of undefined". The ?. stops safely at the missing part and returns undefined instead of crashing the whole script.

Note: Output: Bengaluru undefined

Nullish coalescing ?? — a smarter default

The ?? operator supplies a fallback value, but only when the left side is null or undefined (the two "truly missing" values). This fixes a long-standing bug with the older || operator, which also treats 0 and "" (empty string) as "missing" — even though they are real, valid values.

?? respects 0 and ""; || does not
<script>
  const stock = 0;            // a real value: zero items in stock

  document.write("With ||: " + (stock || "unknown") + "<br>");   // "unknown" — WRONG
  document.write("With ??: " + (stock ?? "unknown"));            // 0 — correct
</script>
Live preview

Here stock is 0 — a perfectly valid count. stock || "unknown" wrongly replaces it with "unknown", because || treats 0 as "empty". But stock ?? "unknown" keeps the 0, because 0 is not null or undefined. Use ?? for defaults whenever 0 or "" could be legitimate values.

Note: Output: With ||: unknown With ??: 0

Watch out: Common bug: using || for default values when 0, "" or false are legitimate. Reach for ?? when you only want to replace genuinely missing (null/undefined) values.

Set — a list with no duplicates

A Set is a collection like an array, but it automatically refuses duplicates. The most common use is removing repeats from a list in one line.

Set removes duplicates instantly
<script>
  const tags = ["js", "css", "js", "html", "css", "js"];
  const unique = [...new Set(tags)];       // de-duplicate
  document.write(unique.join(", "));
</script>
Live preview

new Set(tags) builds a Set from the array, and because a Set ignores repeats, only one of each value survives. The spread [...new Set(tags)] pours those unique values back into a normal array, giving the de-duplicated list — a tidy one-line trick used everywhere.

Note: Output: js, css, html

Map — keyed lookups (any key type)

A Map is like an object: it stores key → value pairs. The differences are that a Map keeps its items in insertion order, lets keys be any type (not just strings), and has handy methods like .set, .get and .size.

Map: set, get and size
<script>
  const scores = new Map();
  scores.set("Asha", 90);
  scores.set("Ravi", 75);

  document.write("Asha: " + scores.get("Asha") + "<br>");
  document.write("Players: " + scores.size);
</script>
Live preview

new Map() creates an empty Map. .set("Asha", 90) stores a pair, and .get("Asha") reads the value back (90). .size counts the pairs — like .length for arrays. Maps shine when you build up keyed data and want easy reading and counting.

Note: Output: Asha: 90 Players: 2

Tip: Rule of thumb: use a plain object for fixed, known fields (a user’s name/age); use a Map when you keep adding/looking up pairs by key; use a Set when you just need unique values.

Q. Why prefer ?? over || for a default value?

Answer: ?? treats only null and undefined as "missing", so legitimate values like 0 and "" are preserved. || would wrongly replace them.

✍️ Practice

  1. Write a function with a rest parameter that returns the largest of any number of arguments.
  2. Use ?. to safely read a nested property that may be missing, and ?? to give it a default.
  3. De-duplicate an array of repeated values using a Set.

🏠 Homework

  1. Take a small dataset (array of user objects) and use optional chaining + nullish coalescing to print a field that some users are missing, with a sensible default.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →