What’s New in ECMAScript? Deep Dive into Recent TC39 Proposals and Stage Advances
This article reviews the latest TC39 proposals—including findLast, Symbol as WeakMap keys, JSON.parse source text access, String.dedent, Import Reflection, RegExp modifiers and atomic operators, and Faster Promise Adoption—detailing their stage progress, implementation requirements, and practical code examples for modern JavaScript development.
In the recent TC39 meeting, the findLast proposal advanced to Stage 4, marking the second proposal from Chinese developers to reach this stage, while String Dedent and JSON.parse source text access also made notable progress.
Stage 3 → Stage 4
Advancing from Stage 3 to Stage 4 requires:
Writing TC39/test262 tests covering the proposal and having them merged.
At least two implementations passing the Test262 suite and shipping in a release.
Submitting a Pull Request to integrate the proposal into the official ECMAScript standard and obtaining editorial approval.
findFromLast
Proposal link: https://tc39.es/proposal-array-find-from-last/index.html
The proposal adds findLast and findLastIndex methods to Array and TypedArray, enabling searches from the end of an array.
Previously, achieving the same required reversing a copy of the array: [...[]].reverse().find(); Similarly, Array.findIndex needed extra steps to obtain the last matching index.
const arr = [1, 2, 3, 4];
arr.length - 1 - [...arr].reverse().findIndex(i => i % 2 === 1); // 2With the new APIs, the intent becomes straightforward:
const arr = [1, 2, 3, 4];
arr.findLast(i => i % 2 === 1); // 3
arr.findLastIndex(i => i % 2 === 1); // 2
arr.findLastIndex(i => i % 2 === 10); // -1These methods are already available in Chrome 97 and can be polyfilled via core‑js or es‑shims.
Symbol as WeakMap Keys
Proposal link: https://github.com/tc39/proposal-symbols-as-weakmap-keys
The proposal permits Symbol values as keys in WeakMap, which previously accepted only objects. This enables storing references in Records and Tuples, which rely on value‑based equality.
const weakMap = new WeakMap();
const key = Symbol('ref for data');
const data = {};
weakMap.set(key, data);Symbols can be Unique, Well‑known, or Registered. Only Unique and Well‑known symbols are allowed as WeakMap keys; Registered symbols are excluded because they cannot be observed for garbage collection.
JSON.parse source text access
Proposal link: https://github.com/tc39/proposal-json-parse-with-source
The proposal adds a third source argument to the reviver function of JSON.parse, allowing the original text to be used for transformations, e.g., preserving large integers:
const tooBig = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
const reviver = (key, val, {source}) => typeof val === "number" && val % 1 === 0 ? BigInt(source) : val;
const roundTripped = JSON.parse(String(tooBig), reviver);
// roundTripped === tooBig → trueIt also introduces JSON.rawJSON for JSON.stringify to prevent double‑serialization of values:
JSON.stringify(9999999999999999n, (k, v) => JSON.rawJSON(v)); // "9999999999999999"String Dedent
Proposal link: https://github.com/tc39/proposal-string-dedent String.dedent removes common indentation from multi‑line template literals, aligning the source code with the resulting string.
class Foo {
methodA() {
const foo = String.dedent(`
create table student(
id int primary key,
name text
)
`);
return foo;
}
}Import Reflection
Proposal link: https://github.com/tc39/proposal-import-reflection
The proposal extends import statements with an as clause to attach reflection metadata, useful for specifying WebAssembly import types:
import FooModule from "./foo.wasm" as "wasm-module";
FooModule instanceof WebAssembly.Module; // trueIt differs from Import Assertion, which adds type assertions without affecting execution semantics.
Regular Expression Pattern Modifiers for ECMAScript
Proposal link: https://github.com/tc39/proposal-regexp-modifiers
The proposal introduces scoped pattern modifiers using the syntax (?imsx-imsx:subexpression), allowing flags to be enabled or disabled for specific sub‑expressions.
const re1 = /^[a-z](?-i:[a-z])$/i;
re1.test("ab"); // true
re1.test("Ab"); // true
re1.test("aB"); // falseRegular Expression Atomic Operators for ECMAScript
Proposal link: https://github.com/tc39/proposal-regexp-atomic-operators
Atomic groups ( (?>…)) and possessive quantifiers ( n*+, n++, etc.) prevent backtracking, improving performance and predictability.
const re = /a(?>bc|b)c/; // atomic group prevents backtrack
re.test("abc"); // false
re.test("abcc"); // trueFaster Promise Adoption
Proposal link: https://github.com/tc39/proposal-faster-promise-adoption
The proposal allows a promise to adopt the state of another promise without an extra tick, reducing asynchronous overhead.
const outer = new Promise(res => {
const inner = Promise.resolve(1);
res(inner);
});
outer.then(log); // resolves in one tick instead of twoThis optimization is significant for async/await patterns where nested promises can otherwise introduce unnecessary micro‑task cycles.
Conclusion
The JavaScript Chinese Interest Group (JSCIG) invites developers to discuss ECMAScript topics on GitHub: https://github.com/JSCIG/es-discuss/discussions .
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.
