What's New (2024-2026)
Set methods, Object.groupBy, Promise.withResolvers, Temporal.
TC39 ships a JavaScript spec every year, ratified each June. The last few rounds have been unusually good: tiny conveniences that delete chunks of code you used to write. Here's a guided tour of the wins from ES2024 through ES2026, the current edition, so you stop polyfilling things that are already built in.
Array.fromAsync) shipped in browsers years before they were ratified. Others sit at Stage 4, implemented and finished, waiting for the next edition to be cut. Check support, not the edition number.Object.groupBy and Map.groupBy (ES2024)
The bucket-by-key reduce you write every other day is now a method:
const items = [
{ name: "apple", type: "fruit" },
{ name: "carrot", type: "veg" },
{ name: "pear", type: "fruit" },
];
Object.groupBy(items, x => x.type);
// {
// fruit: [{name:"apple",...}, {name:"pear",...}],
// veg: [{name:"carrot",...}]
// }
// Need a Map (e.g. for non-string keys)?
Map.groupBy(items, x => x.type);Promise.withResolvers (ES2024)
Build a promise plus its resolve and reject handles in one line, without the closure ceremony:
const { promise, resolve, reject } = Promise.withResolvers();
button.addEventListener("click", () => resolve("clicked!"));
await promise; // "clicked!"Promise.try (ES2025)
Run a function that might be sync or async and treat both the same:
// Wraps the call in a promise so sync throws and async rejections
// both end up in .catch
Promise.try(() => doMaybeAsyncThing())
.then(value => /* ... */)
.catch(err => /* ... */);Set methods (ES2025)
Sets finally got the math operations you've been writing by hand:
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
a.union(b); // Set {1, 2, 3, 4}
a.intersection(b); // Set {2, 3}
a.difference(b); // Set {1}
a.symmetricDifference(b);// Set {1, 4}
a.isSubsetOf(b); // false
a.isSupersetOf(b); // false
a.isDisjointFrom(b); // falseIterator helpers (ES2025)
Array methods on lazy iterators (see the iterators lesson for more):
function* naturals() {
let n = 1;
while (true) yield n++;
}
naturals()
.filter(n => n % 2 === 0)
.map(n => n * n)
.take(5)
.toArray(); // [4, 16, 36, 64, 100]RegExp.escape (ES2025)
Stop hand-escaping user input before stuffing it into a regex:
const userInput = "1 + 2 * 3";
const pattern = new RegExp(RegExp.escape(userInput), "g");
// Without RegExp.escape, the special chars (+ * .) would blow up the regexAbortSignal.any and AbortSignal.timeout
// One signal that fires when ANY of these abort
const signal = AbortSignal.any([
userCancel.signal,
AbortSignal.timeout(5000),
]);
await fetch("/api/data", { signal });structuredClone
Real deep clone, built in. Handles dates, maps, sets, typed arrays, and cyclic references:
const original = { a: 1, when: new Date(), nested: { b: 2 } };
const clone = structuredClone(original);
clone.nested.b = 99;
original.nested.b; // 2 - unchangedstructuredClone doesn't clone functions, DOM nodes, or class instances (those become plain objects). For normal data shapes, it's the answer.Temporal (shipping, but not everywhere)
Date is universally hated. Temporal is its replacement: timezone-aware, immutable, and it separates wall time from instants instead of pretending they are the same thing. It has gone from "someday" to "in two of three engines".
- Firefox 139 shipped it first, in May 2025.
- Chrome and Edge 144 followed in January 2026.
- Safari has not shipped it. WebKit still lists it as in development.
- Node 26 and Deno 2.7 have it.
const now = Temporal.Now.zonedDateTimeISO("America/New_York");
const tomorrow = now.add({ days: 1 });
const birthday = Temporal.PlainDate.from("1990-04-12");
const age = Temporal.PlainDate.from(Temporal.Now.plainDateISO())
.since(birthday, { largestUnit: "years" }).years;Object.hasOwn (ES2022, easy to miss)
Quick mention because people still write the verbose form:
// Old
Object.prototype.hasOwnProperty.call(obj, "key")
// New
Object.hasOwn(obj, "key")The cheat sheet
- Group an array:
Object.groupBy - Promise resolve outside constructor:
Promise.withResolvers - Set math:
.union,.intersection,.difference - Lazy chains: iterator helpers
- Cancel many ways:
AbortSignal.any,AbortSignal.timeout - Deep copy:
structuredClone - Escape regex input:
RegExp.escape - Sync-or-async kickoff:
Promise.try
Try them in one playground
Quiz
Which built-in deep-clones an object including Dates and Maps?
Recap
Object.groupBy,Promise.withResolversand the new Set methods delete code you used to write.- Iterator helpers turn generators into lazy data pipelines.
structuredCloneis the right default for deep copies of data.AbortSignal.anyandAbortSignal.timeoutmake cancellation composable.- Temporal replaces
Date. It ships in Firefox, Chrome, and Node 26, but not Safari, so browser code still needs the polyfill.