What's New (2024-2026)
Set methods, Object.groupBy, Promise.withResolvers, Temporal.
TC39 ships a JavaScript spec every year. 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, ES2025, and what's landing in ES2026, so you stop polyfilling things that are already built in.
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 (ES2026, broadly available)
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 (ES2026)
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 - unchangedstructuredClonedoesn't clone functions, DOM nodes, or class instances (those become plain objects). For normal data shapes, it's the answer.Temporal (in preview)
Date is universally hated. Temporal is its replacement: timezone-aware, immutable, separates wall time from instants. Behind a polyfill today, becoming standard in browsers.
// Future / polyfilled syntax - the shape of things to come
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 is coming for
Date. Start learning the shape now via the polyfill.