ECMAScript 2024: pragmatic evolution
The ECMAScript 2024 specification (ES15) was officially approved in June 2024 and brings features that many developers had been requesting for years. Unlike previous versions that focused on syntax, ES2024 focuses on practical utilities that simplify day-to-day code.
Object.groupBy() and Map.groupBy()
Without a doubt, the star of ES2024. Object.groupBy() lets you group elements of an iterable using a classifier function.
Before vs. Now
// BEFORE: manual grouping with reduce
const porCategoria = productos.reduce((acc, producto) => {
const key = producto.categoria;
if (!acc[key]) acc[key] = [];
acc[key].push(producto);
return acc;
}, {});
// NOW: a single line
const porCategoria = Object.groupBy(productos, p => p.categoria);Map.groupBy() for non-string keys
When you need keys that are not strings (objects, numbers, etc.), use Map.groupBy():
const usuarios = [
{ nombre: 'Ana', edad: 25 },
{ nombre: 'Carlos', edad: 17 },
{ nombre: 'Diana', edad: 30 },
{ nombre: 'Luis', edad: 15 },
];
const porMayoriaEdad = Map.groupBy(usuarios, u =>
u.edad >= 18 ? 'adulto' : 'menor'
);
// Map { 'adulto' => [...], 'menor' => [...] }Important considerations
Object.groupBy()creates an object without a prototype (Object.create(null))- Keys are converted to strings (as in regular objects)
- For complex keys, use
Map.groupBy() - The original iterable is not modified
Promise.withResolvers()
This new static method simplifies a very common pattern: creating a Promise and extracting its resolve and reject functions.
// BEFORE: common but verbose pattern
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
// NOW: clean and direct
const { promise, resolve, reject } = Promise.withResolvers();Real-world use case: wrapping an EventEmitter
function esperarEvento(emitter, evento) {
const { promise, resolve, reject } = Promise.withResolvers();
emitter.addEventListener(evento, resolve, { once: true });
emitter.addEventListener('error', reject, { once: true });
return promise;
}
// Usage
const resultado = await esperarEvento(socket, 'message');Resizable and transferable ArrayBuffer
ES2024 introduces ArrayBuffer with adjustable size and the ability to transfer ownership between contexts.
Resizable ArrayBuffer
// Create a buffer that can grow up to 1MB
const buffer = new ArrayBuffer(256, { maxByteLength: 1024 * 1024 });
console.log(buffer.byteLength); // 256
console.log(buffer.maxByteLength); // 1048576
console.log(buffer.resizable); // true
// Resize
buffer.resize(512);
console.log(buffer.byteLength); // 512ArrayBuffer transfer
const original = new ArrayBuffer(1024);
const view = new Uint8Array(original);
view[0] = 42;
// Transfer to a new buffer
const transferido = original.transfer();
console.log(original.byteLength); // 0 (detached)
console.log(transferido.byteLength); // 1024
console.log(new Uint8Array(transferido)[0]); // 42This is especially useful when communicating with Web Workers, eliminating the need to copy data.
String.isWellFormed() and String.toWellFormed()
JavaScript allows strings with incomplete surrogate pairs, which can cause problems when interacting with APIs like encodeURIComponent(). These new methods solve that.
const texto = 'Hola \uD800 mundo'; // lone surrogate
console.log(texto.isWellFormed()); // false
const textoCorregido = texto.toWellFormed();
console.log(textoCorregido.isWellFormed()); // true
// Replaces lone surrogates with U+FFFD (replacement character)When to use them?
- Before sending strings to external APIs
- When processing data from untrusted sources
- When using
TextEncoderorencodeURIComponent()
Atomics.waitAsync()
An asynchronous version of Atomics.wait() that does not block the main thread:
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// Does not block the main thread
const resultado = Atomics.waitAsync(sharedArray, 0, 0);
if (resultado.async) {
resultado.value.then(status => {
console.log('Worker notificado:', status);
});
}
// In another Worker:
Atomics.store(sharedArray, 0, 1);
Atomics.notify(sharedArray, 0);RegExp v flag (unicodeSets)
The new v flag extends regular expression capabilities with Unicode character sets:
// Search for emojis (with v flag)
const emojiRegex = /\p{RGI_Emoji}/v;
console.log(emojiRegex.test('hola')); // false
// Set intersection: Greek letters that are uppercase
const regex = /[\p{Script=Greek}&&\p{Lu}]/v;
console.log(regex.test('A')); // false (Latin)
// Set difference: letters except vowels
const consonantes = /[\p{Letter}--[aeiouAEIOU]]/v;Set operations with the v flag
| Operation | Syntax | Description |
|---|---|---|
| Union | [AB] |
A or B |
| Intersection | [A&&B] |
A and B |
| Difference | [A--B] |
A but not B |
Browser support summary
| Feature | Chrome | Firefox | Safari | Node.js |
|---|---|---|---|---|
| Object.groupBy | 117+ | 119+ | 17.4+ | 21+ |
| Promise.withResolvers | 119+ | 121+ | 17.4+ | 22+ |
| ArrayBuffer.transfer | 114+ | 122+ | 17.4+ | 22+ |
| String.isWellFormed | 111+ | 119+ | 16.4+ | 20+ |
| Atomics.waitAsync | 87+ | 128+ | 16.4+ | 16+ |
| RegExp v flag | 112+ | 116+ | 17+ | 20+ |
Conclusion
ES2024 brings improvements that, while not as flashy as arrow functions or async/await, solve real day-to-day development friction. Object.groupBy() and Promise.withResolvers() in particular will change the way we write JavaScript. The best part: they already have broad support across all modern browsers. It is time to adopt them.



Comments (0)
Sign in to comment