ES15 Interactive Hub — ECMAScript 2024
Object.groupBy() for grouping data, Promise.withResolvers for event-driven code, Array.fromAsync, the RegExp v flag, String.isWellFormed/toWellFormed for UTF-16 safety, non-blocking Atomics.waitAsync — a richer functional + async toolkit.
Object.groupBy() & Map.groupBy()
Core topic
💡 Concept summary
Group array elements by a key computed from a callback — replacing the clunky reduce + push pattern.
🤔 Why do you need this feature?
Group by is an extremely common data operation (by category, by date, by status...). Previously you had to write a reduce with an object accumulator yourself — long and error-prone. ES15 adds 2 standard static methods for this.
// Before ES15 — use reduce yourself
var users = [
{ name: 'Lan', age: 25, role: 'dev' },
{ name: 'Nam', age: 30, role: 'pm' },
{ name: 'Hoa', age: 25, role: 'dev' },
];
var byRole = users.reduce(function(acc, u) {
if (!acc[u.role]) acc[u.role] = [];
acc[u.role].push(u);
return acc;
}, {});
console.log(byRole);
// { dev: [Lan, Hoa], pm: [Nam] }// ES15 — Object.groupBy & Map.groupBy
const users = [
{ name: 'Lan', age: 25, role: 'dev' },
{ name: 'Nam', age: 30, role: 'pm' },
{ name: 'Hoa', age: 25, role: 'dev' },
];
const byRole = Object.groupBy(users, u => u.role);
console.log(byRole);
// { dev: [Lan, Hoa], pm: [Nam] }
// Map version — preserves key order + accepts object/symbol as key
const byAge = Map.groupBy(users, u => u.age);
console.log(byAge.get(25)); // [Lan, Hoa]
// Group by range/condition
const byAdult = Object.groupBy([1, 5, 18, 22, 17], n =>
n >= 18 ? 'adult' : 'minor'
);ES15 Quick Reference
Quick syntax overview + copy snippets
Group array elements by a key computed from a callback — replacing the clunky reduce + push pattern.
const users = [
{ name: 'Lan', age: 25, role: 'dev' },
{ name: 'Nam', age: 30, role: 'pm' },
...Create a Promise and simultaneously obtain resolve/reject in an outer scope — no need to declare variables first then assign them inside the constructor.
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => resolve("Done!"), 500);
promise.then(console.log);
...Create an array from an async iterable or an iterable containing promises — the async version of Array.from().
async function* gen() {
yield 1; yield 2; yield 3;
}
...The "/v" flag for regex supports advanced set notation: intersection and subtraction between Unicode property sets.
const re = /[\p{L}--\p{ASCII}]/gv;
console.log('café Hello 中文'.match(re));
const han = /[\p{L}&&\p{Script=Han}]/gv;
...A pair of methods to check and fix UTF-16 strings containing lone surrogates (broken Unicode characters) — important when receiving data from a DB/network with corrupted encoding.
const good = "Xin chào 👋"; // the emoji is a valid surrogate pair const bad = "Hello\uD800World"; // lone high surrogate console.log(good.isWellFormed()); // true ...
The NON-BLOCKING version of Atomics.wait — waits for a shared memory value to change without freezing the thread. Important for the browser main thread (which is not allowed to block).
const sab = new SharedArrayBuffer(4); const view = new Int32Array(sab); const result = Atomics.waitAsync(view, 0, 0, 1000); ...