New TC39 Stage 3‑4 Proposals: .at(), Object.hasOwn, Pipeline Operator, and More

The article reviews the recent TC39 meeting, outlines the criteria for advancing proposals to Stage 4, and explains several upcoming ECMAScript features—including the relative‑indexing .at() method, Object.hasOwn, class static initialization blocks, the pipeline operator, and other proposals—providing code examples and implementation status.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
New TC39 Stage 3‑4 Proposals: .at(), Object.hasOwn, Pipeline Operator, and More

Stage 3 → Stage 4

Moving a proposal from Stage 3 to Stage 4 requires:

Writing tc39/test262 tests that cover the proposal.

At least two JavaScript engines or transpilers passing those tests and shipping the feature.

Submitting a pull‑request to tc39/ecma262 that is signed off by the ECMAScript editor.

Relative indexing .at() method

The proposal adds a generic .at method to any indexable type (Array, String, TypedArray) so that negative indices work like Python’s arr[-1]. Example:

[0, 1, 2, 3].at(-1); // => 3
'0123'.at(-1); // => '3'

This feature is enabled by default in Chrome 92 and Firefox 90.

Object.hasOwn

To avoid the pitfalls of calling obj.hasOwnProperty when the property may be overridden, the proposal adds Object.hasOwn as a safe static method:

let obj = { foo: false };
Object.hasOwn(obj, "foo"); // true
let obj2 = Object.create({ foo: true });
Object.hasOwn(obj2, "foo"); // false
let obj3 = Object.create(null);
Object.hasOwn(obj3, "foo"); // false

The method is slated to be enabled by default in Chrome 93 and Firefox 91.

Class static initialization blocks

Static blocks allow code to run during class evaluation and have access to private fields. Example:

let getX;
export class C {
  #x;
  constructor(x) { this.#x = { data: x }; }
  static { getX = obj => obj.#x; }
}
export function readXData(obj) { return getX(obj).data; }

This feature will be enabled by default in Firefox 93 and Chrome 94.

Change Array by Copy

The proposal introduces copy‑based versions of mutating array methods so that immutable data structures like Tuple can use them. Example:

let arr = [3, 2, 1];
arr.sort(); // arr becomes [1, 2, 3]
let sorted = arr.withSorted(); // sorted => [1, 2, 3], arr stays [3, 2, 1]

Pipeline operator

The pipeline operator ( |>) propagates a value through a sequence of function calls, making nested or async calls more readable. Example:

foo(bar(1, baz(x)[0]).method())
// becomes
x |> baz(%)[0] |> bar(1, %).method() |> foo(%)

let text = await fetch(url) |> await %.text();

Stage 0 → Stage 1

Advancing a proposal from Stage 0 to Stage 1 requires:

Finding a TC39 champion to shepherd the proposal.

Clearly stating the problem, the need, and a rough solution.

Providing concrete examples of the problem and the solution.

Discussing the API shape, algorithms, semantics, and implementation risks.

String.isUSVString

This static method validates whether a string is a valid Unicode Scalar Value (USV). Example:

String.isUSVString('\ud800'); // false
String.isUSVString('\ud800\udc00'); // true

Array.fromAsync

The proposal adds Array.asyncFrom (named Array.fromAsync in the spec) to create an array from an async iterator. Example:

const fs = require('fs');
async function print(readable) {
  readable.setEncoding('utf8');
  const data = (await Array.asyncFrom(readable)).join('');
  console.log(data);
}
print(fs.createReadStream('file')).catch(console.error);

BigInt Math

Math functions such as Math.max and Math.pow will gain overloads that accept BigInt arguments, while functions that could lose precision (e.g., trigonometric and logarithmic functions) will remain unavailable for BigInt.

Get Intrinsic

The proposal introduces a built‑in getIntrinsic function that returns intrinsic objects and methods without relying on eval or specific syntax. Example:

const GeneratorFunction = getIntrinsic('%GeneratorFunction%');
const AsyncGeneratorFunction = getIntrinsic('%AsyncGeneratorFunction%');

Fixed layout objects

Fixed layout objects (structs) provide sealed, non‑extendable objects that can be shared with WebAssembly GC. Two kinds are proposed: ordinary structs and shared structs. Example of an ordinary struct:

struct class Box {
  x;
  getX() { return this.x; }
}
let box = new Box();
box.x = 42; // ok
box.y = 8; // throws because the struct is sealed

Shared structs can be transferred between workers but cannot have instance methods other than static ones.

Conclusion

The JavaScript Chinese Interest Group (JSCIG) continues to discuss these and other ECMAScript proposals on GitHub; developers are encouraged to join the conversation.

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.

JavaScriptlanguage featuresTC39ECMAScript proposals
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.