Class Fields Reach Stage 4 – How This Changes JavaScript Development
The article reviews the recent TC39 meeting where the Class Fields proposal advanced to Stage 4, outlines the criteria for moving between proposal stages, and summarizes several other ECMAScript proposals—including Intl.LocaleInfo, Object.hasOwn, Symbol as WeakMap keys, extended timezone options, copy‑based array methods, and readonly ArrayBuffer—detailing their goals, status, and example code.
In this meeting, the highly‑watched Class Fields proposal finally advanced to Stage 4, becoming part of the ECMAScript standard.
Stage 3 → Stage 4
Moving from Stage 3 to Stage 4 requires:
Writing tc39/test262 tests that cover the proposal and merging them into test262.
At least two implementations passing the Test262 suite and shipping in a formal release.
Submitting a pull request that incorporates the proposal into the official ECMA‑262 text and obtaining the ECMA‑262 editor’s sign‑off.
Relevant repositories:
https://github.com/tc39/test262
https://github.com/tc39/ecma262
Class Fields
Proposal links:
https://github.com/tc39/proposal-class-fields
https://github.com/tc39/proposal-private-methods
https://github.com/tc39/proposal-static-class-features
Before the proposal, class fields had to be created inside the constructor, which is not declarative and makes code harder to read. The new syntax lets developers declare fields directly on the class, improving readability and enabling more robust API designs.
JavaScript engines also expose many internal slots (e.g., [[MapData]]) that are only accessible from the engine. The proposal brings a similar mechanism to pure JavaScript, allowing library and runtime authors to create private fields safely.
Example (TypeScript with useDefineForClassFields):
class Base {
name: string;
constructor() {
this.initProps();
}
initProps() {
this.name = 'xxx';
}
}
class Derived extends Base {
age: number;
initProps() {
super.initProps();
this.age = 10;
}
}
const d = new Derived();
console.log(d.age);Stage 2 → Stage 3
Requirements for moving from Stage 2 to Stage 3:
Writing a complete standard text reviewed and signed by a TC39 member.
Obtaining the ECMA‑262 editor’s sign‑off.
Intl.LocaleInfo
Proposal adds APIs to Intl for retrieving user locale preferences such as the first day of the week, weekend definition, and text direction.
let zhHans = new Intl.Locale("zh-Hans");
zhHans.weekInfo; // {firstDay: 1, weekendStart: 6, weekendEnd: 7, minimalDays: 4}
zhHans.textInfo; // {direction: "ltr"}Object.hasOwn
The proposal introduces Object.hasOwn as a safer alternative to Object.prototype.hasOwnProperty, avoiding issues when the method is overridden.
let object = { foo: false };
Object.hasOwn(object, "foo"); // true
let object2 = Object.create({ foo: true });
Object.hasOwn(object2, "foo"); // false
let object3 = Object.create(null);
Object.hasOwn(object3, "foo"); // falseSymbol as WeakMap Keys
This proposal allows Symbol values to be used as keys in WeakMap, enabling weak references to objects via symbols and supporting use‑cases in Records & Tuples.
class RefBookkeeper {
#references = new WeakMap();
ref(obj) {
const sym = Symbol();
this.#references.set(sym, obj);
return sym;
}
deref(sym) { return this.#references.get(sym); }
}
globalThis.refs = new RefBookkeeper();
const server = {
port: 8080,
handler: refs.ref(function handler(req) { /* … */ })
};
refs.deref(server.handler)({ /* …req */ });Extend Timezone Options
The proposal expands the timeZoneName option of Intl.DateTimeFormat with additional formats such as shortOffset, longWall, etc.
let timeZoneNames = ["short","long","shortOffset","longOffset","shortWall","longWall"];
timeZoneNames.forEach(name => {
console.log(new Date().toLocaleTimeString("zh-Hans", {timeZoneName: name}));
});Change Array By Copy
To support immutable data structures like Tuple, this proposal adds non‑mutating copies of array‑mutating methods (e.g., sorted()) so that the original array remains unchanged.
let arr = [3,2,1];
arr.sort(); // arr becomes [1,2,3]
arr = [3,2,1];
let sorted = arr.sorted(); // sorted is [1,2,3], arr stays [3,2,1]Readonly ArrayBuffer & ArrayBufferView
The proposal adds a freeze -like capability to ArrayBuffer and its views, preventing writes to the underlying memory.
const buffer = new ArrayBuffer(4);
const view = new Int32Array(buffer);
view[0] = 42; // OK
buffer.freeze();
view[0] = 42; // TypeError
buffer.isFrozen(); // trueAll of these proposals are already implemented in environments such as Chrome 74, Node 12, Safari Technology Preview 117, TypeScript 3.8, and Babel 7+, though some implementations may differ before the final standard is locked.
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.
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.
