What’s New in ECMAScript? A Deep Dive into Stage 3‑4 TC39 Proposals

This article reviews the latest TC39 proposals advancing from Stage 3 to Stage 4—including Promise.any, AggregateError, WeakRefs, FinalizationRegistry, logical assignment operators, numeric literal separators, Intl.ListFormat, Intl.DateTimeFormat styles, iterator.item, Intl.Segmenter, Record & Tuple, JSON.parse source‑text access, await extensions, Array.prototype.unique, and resizable array buffers—explaining their goals, required thresholds, and providing concrete code examples.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
What’s New in ECMAScript? A Deep Dive into Stage 3‑4 TC39 Proposals

Stage 3 → Stage 4

To move from Stage 3 to Stage 4 a proposal must satisfy several criteria:

Provide a complete tc39/test262 test suite that validates compatibility across JavaScript engines and transpilers.

At least two implementations must pass the Test262 suite and ship the feature in a released version.

Submit a pull request to tc39/ecma262 that incorporates the proposal into the official ECMAScript specification, signed off by the ECMAScript editor.

Promise.any & AggregateError

Proposal link: https://github.com/tc39/proposal-promise-any

Promise.any resolves as soon as any input promise resolves; if all promises reject, it rejects with an AggregateError that aggregates the individual errors via the AggregateError.errors property.

Promise.any([
  fetch('https://example.com/').then(() => 'home'),
  fetch('https://example.com/blog').then(() => 'blog'),
  fetch('https://example.com/docs').then(() => 'docs')
]).then(first => {
  console.log(first); // → 'home'
}).catch(error => {
  console.log(error);
});

WeakRefs & FinalizationRegistry

Proposal link: https://github.com/tc39/proposal-weakrefs/

WeakRefs allow weak references to objects without preventing garbage collection. FinalizationRegistry provides a callback mechanism (similar to a destructor) that receives a heldValue identifying the reclaimed object.

const cache = new Map();
const finalizationGroup = new FinalizationRegistry(name => {
  const ref = cache.get(name);
  if (ref !== undefined && ref.deref() === undefined) {
    cache.delete(name);
  }
});
function getImageCached(name) {
  const ref = cache.get(name);
  if (ref !== undefined) {
    const deref = ref.deref();
    if (deref !== undefined) return deref;
  }
  const image = performExpensiveOperation(name);
  const wr = new WeakRef(image);
  cache.set(name, wr);
  finalizationGroup.register(image, name);
  return image;
}

Logical Assignment

Proposal link: https://github.com/tc39/proposal-logical-assignment

Introduces three new operators: a ||= b (logical OR assignment) a &&= b (logical AND assignment) a ??= b (nullish coalescing assignment)

// Or assignment
a ||= b; // equivalent to a || (a = b)
// And assignment
a &&= b; // equivalent to a && (a = b)
// Nullish assignment
a ??= b; // equivalent to a ?? (a = b)
function example(opts) {
  opts.foo = opts.foo ?? 'bar';
  opts.baz ??= 'qux';
}

Numeric Literal Separator

Proposal link: https://github.com/tc39/proposal-numeric-separator

Allows the underscore ( _) as a visual separator in numeric literals to improve readability.

10_0000_0000; // 1 000 000 000
let fee = 123_00; // 12 300 (cents)
let amount = 1_234_500; // 1,234,500
0.000_001; // 1 µ
1e10_000; // 10^(10 000)

Intl.ListFormat

Proposal link: https://github.com/tc39/proposal-intl-list-format

Provides locale‑aware list formatting.

let lfmt = new Intl.ListFormat('zh', {type: 'conjunction', style: 'long'});
console.log(lfmt.format(['Anne', 'John', 'Mike'])); // "Anne、John和Mike"

Intl.DateTimeFormat dateStyle/timeStyle

Proposal link: https://github.com/tc39/proposal-intl-datetime-style

Introduces dateStyle and timeStyle options for locale‑appropriate formatting without manually specifying individual components.

let dtf = new Intl.DateTimeFormat('zh', {dateStyle: 'short'});
console.log(dtf.format(new Date())); // "2020/7/27"
let dtf2 = new Intl.DateTimeFormat('en-US', {dateStyle: 'short'});
console.log(dtf2.format(new Date())); // "7/27/20"

iterator.items()

Proposal link: https://github.com/tabatkins/proposal-item-method

Provides an .item method on any indexable object (Array, String, TypedArray) to retrieve elements using positive or negative indices, similar to Python’s negative indexing.

let arr = [10, 20, 30];
console.log(arr.item(-1)); // 30
console.log('hello'.item(-2)); // 'l'

Intl.Segmenter

Proposal link: https://github.com/tc39/proposal-intl-segmenter

Implements Unicode Text Segmentation (UAX 29) for word, sentence, and grapheme segmentation.

let segmenter = new Intl.Segmenter('zh', {granularity: 'word'});
let input = "我不是,我没有,你别瞎说。";
for (let {segment, index, isWordLike} of segmenter.segment(input)) {
  console.log(`segment at ${index}: «${segment}»${isWordLike ? ' (word‑like)' : ''}`);
}

Record and Tuple

Proposal link: https://github.com/tc39/proposal-record-tuple

Introduces immutable primitive types Record (object‑like) and Tuple (array‑like) with value‑based equality.

const grid = new Map([
  [#[0,0], 'player'],
  [#{x:3, y:5}, 'enemy']
]);
console.log(grid.get(#[0,0])); // player
console.log(grid.get({x:3, y:5})); // undefined

JSON.parse source‑text access

Proposal link: https://github.com/tc39/proposal-json-parse-with-source

Extends JSON.parse reviver and JSON.stringify replacer with access to the raw source text and a rawTag symbol, enabling precise handling of large numbers and custom types.

// Reviver can read the original source
JSON.parse(' 9999999999999999', (k, v, {source}) => BigInt(source)); // → 9999999999999999n
// Replacer can emit raw source for custom serialization
JSON.stringify(9999999999999999n, (k, v, {rawTag}) => ({[rawTag]: String(v)})); // → "9999999999999999"

await operations

Proposal link: https://github.com/tc39-transfer/proposal-await.ops

Proposes syntactic sugar such as await.all, await.race, await.any to make common Promise combinators more readable.

// before
await Promise.all(users.map(async x => fetchProfile(x.id)));
// after
await.all users.map(async x => fetchProfile(x.id));

Array.prototype.unique()

Proposal link: https://github.com/TechQuery/array-unique-proposal

Adds a unique method that can deduplicate complex objects using an optional key‑selector function.

arr.unique(); // similar to [...new Set(arr)]
arr.unique(x => x.id); // deduplicate by id

ResizableArrayBuffer and GrowableSharedArrayBuffer

Proposal link: https://github.com/syg/proposal-resizablearraybuffer

Defines two new buffer types:

ResizableArrayBuffer : can be grown or shrunk in place (implementation‑defined observation behavior).

GrowableSharedArrayBuffer : shared across agents, can only grow.

let rab = new ResizableArrayBuffer(1024, 1024**2);
assert(rab.byteLength === 1024);
assert(rab.maximumByteLength === 1024**2);
rab.resize(rab.byteLength * 2);
assert(rab.byteLength === 2048);

Stage Transition Criteria

General thresholds for moving between stages:

Stage 2 → Stage 3: full specification text reviewed and signed by a TC39 member, plus editor approval.

Stage 1 → Stage 2: a champion, problem statement, examples, and initial design discussion.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptECMAScriptweakrefPromise.anyTC39intlStage 4Stage 3
Alibaba Terminal Technology
Written by

Alibaba Terminal Technology

Official public account of Alibaba Terminal

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.