What’s New in ECMAScript 2024? Exploring Six Major TC39 Proposals
This article reviews the six key ECMAScript 2024 proposals—including well‑formed Unicode strings, asynchronous atomic wait, the new RegExp v flag, ArrayBuffer transfer, array grouping, and Promise.withResolvers—explaining their purpose, API changes, and providing runnable code examples.
Proposal 1: Well-Formed Unicode Strings
JavaScript strings are sequences of UTF‑16 code units, which can represent 65 536 values. Characters outside the BMP are stored as surrogate pairs. The proposal adds String.prototype.isWellFormed() to test for isolated surrogate pairs and String.prototype.toWellFormed() to replace them with U+FFFD.
'a'.length // 1
'🥑'.length // 2
'\ud83e\udd51'.isWellFormed() // true
'\ud83e'.isWellFormed() // false
'\ud83e'.toWellFormed() // �Proposal 2: Asynchronous atomic wait for ECMAScript
Workers use SharedArrayBuffer and Atomics for shared memory. The current Atomics.wait() is synchronous and cannot run on the main thread. The new Atomics.waitAsync() provides an asynchronous wait that can be used on the main thread.
// main thread
let i32a = null;
const w = new Worker("worker.js");
w.onmessage = function (env) { i32a = env.data; };
setTimeout(() => {
Atomics.store(i32a, 0, 1);
Atomics.notify(i32a, 0);
}, 1000);
// worker thread
const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
const i32a = new Int32Array(sab);
postMessage(i32a);
const wait = Atomics.waitAsync(i32a, 0, 0);
if (wait.async) {
wait.value.then(v => console.log(v));
} else {
console.log(wait.value);
}Proposal 3: RegExp v flag with set notation + properties of strings
The new v flag adds Unicode set notation, allowing checks of Unicode string properties, set subtraction ( --), intersection ( &&) and union. It also introduces \q{…} for literal strings. The v flag cannot be combined with u.
// example: exclude 💩
/[\p{RGI_Emoji}--\q{💩}]/v.test('😜'); // true
/[\p{RGI_Emoji}--\q{💩}]/v.test('💩'); // falseProposal 4: ArrayBuffer transfer
Provides ArrayBuffer.prototype.transfer() and transferToFixedLength() to move an ArrayBuffer’s bytes, and a detached getter to check whether a buffer has been transferred.
const buffer = new ArrayBuffer();
buffer.detached; // false
const newBuffer = buffer.transfer();
buffer.detached; // trueProposal 5: Array grouping
Introduces static Object.groupBy / Map.groupBy (and later Array.prototype.groupBy) to group elements by a callback, mirroring Lodash/Ramda groupBy.
const langs = [{name:"Rust",compiled:true,released:2015},{name:"Go",compiled:true,released:2009},{name:"JavaScript",compiled:false,released:1995},{name:"Python",compiled:false,released:1991}];
const langsByType = Object.groupBy(langs, ({compiled}) => compiled ? "compiled" : "interpreted");Proposal 6: Promise.withResolvers
Adds Promise.withResolvers() which returns an object containing a promise and its resolve / reject functions, simplifying patterns that need external resolution.
function createEventsAggregator(eventsCount) {
const events = [];
const {promise, resolve, reject} = Promise.withResolvers();
return {
add: event => {
if (events.length < eventsCount) events.push(event);
if (events.length === eventsCount) resolve(events);
},
abort: () => reject("Events aggregation aborted."),
events: promise,
};
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
