What's New in ES2025 & ES2026 — The Complete Guide with Examples
A bilingual, example-driven tour of ECMAScript 2025 (Iterator Helpers, Set methods, Promise.try, RegExp.escape, import attributes, Float16Array) and ES2026 (explicit resource management with using, Array.fromAsync, Error.isError).
The Annual Release Cycle {Chu kỳ phát hành hàng năm}
Since ES2016, TC39 ships a new ECMAScript edition every June {Từ ES2016, TC39 phát hành một phiên bản ECMAScript mới mỗi tháng Sáu}. A proposal becomes part of the language once it reaches Stage 4 {Một proposal trở thành một phần của ngôn ngữ khi đạt Stage 4}.
- ES2025 (the 16th edition) was finalized on 25 June 2025 {ES2025 (phiên bản thứ 16) được chốt vào 25/06/2025}.
- ES2026 is on track to be approved around June 2026 {ES2026 đang trên đà được duyệt vào khoảng tháng 6/2026}; the features below already reached Stage 4 and ship in modern engines {các tính năng dưới đây đã đạt Stage 4 và có mặt trong các engine hiện đại}.
This is a hands-on tour — every feature has a runnable example {Đây là chuyến đi thực hành — mỗi tính năng đều có ví dụ chạy được}.
Naming note {Ghi chú tên gọi}: “ESxxxx” refers to the year the spec is published, not when engines implement it {“ESxxxx” chỉ năm spec được xuất bản, không phải khi engine triển khai}. Many features land in browsers before the edition is formally approved {Nhiều tính năng đến với trình duyệt trước khi phiên bản được duyệt chính thức}.
Part 1 — ECMAScript 2025 {Phần 1 — ECMAScript 2025}
Iterator Helpers — Lazy Array Methods {Iterator Helpers — Phương thức kiểu Array nhưng lười}
The biggest ergonomic win in ES2025 {Cải thiện trải nghiệm lớn nhất trong ES2025}. Iterators now have .map(), .filter(), .take(), and friends — but unlike arrays, they’re lazy {Iterator giờ có .map(), .filter(), .take(),… — nhưng khác array, chúng lười (lazy)}.
function* naturals() {
let n = 1;
while (true) yield n++; // infinite!
}
const result = naturals()
.map((n) => n ** 2) // 1, 4, 9, 16, ...
.filter((n) => n % 2) // keep odds
.take(5) // stop after 5
.toArray(); // only NOW does work happen
console.log(result); // [1, 9, 25, 49, 81]
Why this matters {Tại sao quan trọng}: with arrays, [...infinite].map().filter() would hang forever because each step builds a full intermediate array {với array, [...infinite].map().filter() sẽ treo mãi vì mỗi bước dựng một array trung gian đầy đủ}. Iterator helpers process one element at a time, on demand, so they work on infinite or huge sequences and avoid intermediate allocations {Iterator helper xử lý từng phần tử một, theo yêu cầu, nên chạy được trên chuỗi vô hạn hay khổng lồ và tránh cấp phát trung gian}.
Available helpers {Các helper có sẵn}: map, filter, flatMap, take, drop, reduce, toArray, forEach, some, every, find, plus the static Iterator.from() {cùng phương thức tĩnh Iterator.from()}.
// Iterator.from() wraps any iterable so you can chain helpers on it
const firstThree = Iterator.from(['a', 'b', 'c', 'd']).take(3).toArray();
console.log(firstThree); // ['a', 'b', 'c']
Set Methods — Real Set Algebra {Set Methods — Đại số tập hợp thật sự}
Set finally gets the mathematical operations we always reimplemented by hand {Set cuối cùng đã có các phép toán mà ta luôn phải tự cài lại bằng tay}.
const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);
a.union(b); // Set {1, 2, 3, 4, 5, 6}
a.intersection(b); // Set {3, 4}
a.difference(b); // Set {1, 2} (in a, not b)
a.symmetricDifference(b);// Set {1, 2, 5, 6} (in exactly one)
a.isSubsetOf(b); // false
a.isSupersetOf(new Set([1, 2])); // true
a.isDisjointFrom(new Set([7, 8])); // true (no overlap)
These return new Sets (non-mutating) and accept any set-like argument {Chúng trả về Set mới (không biến đổi) và nhận bất kỳ đối số dạng set nào}. No more new Set([...a].filter(x => b.has(x))) {Không còn phải viết new Set([...a].filter(x => b.has(x)))}.
Promise.try — Start a Chain Safely {Promise.try — Bắt đầu chuỗi một cách an toàn}
Promise.try(fn) runs fn and always returns a Promise — whether fn returns a value, returns a promise, or throws synchronously {Promise.try(fn) chạy fn và luôn trả về Promise — dù fn trả giá trị, trả promise, hay throw đồng bộ}.
// Problem: a sync throw escapes the promise chain
function getConfig(raw) {
if (!raw) throw new Error('missing config'); // sync throw!
return JSON.parse(raw);
}
// ❌ The throw happens BEFORE any .catch() can catch it
getConfig(input).then(use).catch(handle); // may crash synchronously
// ✅ Promise.try funnels sync + async errors into the same chain
Promise.try(() => getConfig(input))
.then(use)
.catch(handle); // catches the sync throw too
It’s the standardized version of a pattern libraries like Bluebird popularized {Đây là phiên bản chuẩn hóa của một mẫu mà các thư viện như Bluebird đã phổ biến}.
RegExp.escape — Safe Dynamic Patterns {RegExp.escape — Pattern động an toàn}
Building a regex from user input was always risky — special characters like . or ( change the meaning {Dựng regex từ input người dùng luôn rủi ro — ký tự đặc biệt như . hay ( làm đổi ý nghĩa}. RegExp.escape() neutralizes them {RegExp.escape() vô hiệu hóa chúng}.
const userInput = 'a.b(c)';
// ❌ '.' matches any char, '()' is a group → wrong + injection risk
new RegExp(userInput);
// ✅ escape first
const safe = RegExp.escape(userInput); // 'a\\.b\\(c\\)'
const re = new RegExp(safe);
console.log(re.test('a.b(c)')); // true — matches literally
Regex: Inline Modifiers + Duplicate Named Groups {Regex: Cờ inline + nhóm tên trùng}
Inline pattern modifiers let you enable/disable flags for part of a pattern {Cờ inline cho phép bật/tắt flag cho một phần của pattern}:
// (?i:...) → case-insensitive ONLY inside the group
const re = /hello-(?i:world)/;
re.test('hello-WORLD'); // true ('world' part is case-insensitive)
re.test('HELLO-world'); // false ('hello' part is still case-sensitive)
Duplicate named capture groups are now allowed across alternatives {Nhóm tên trùng giờ được phép giữa các nhánh alternation}:
// Previously a SyntaxError; now valid because the names are in
// mutually-exclusive branches of the alternation.
const date = /(?<year>\d{4})-\d{2}|\d{2}-(?<year>\d{4})/;
'2026-05'.match(date).groups.year; // '2026'
'05-2026'.match(date).groups.year; // '2026'
Import Attributes & JSON Modules {Import Attributes & JSON Modules}
You can now import JSON natively, declaring the type with the with keyword {Giờ bạn có thể import JSON một cách gốc, khai báo type bằng từ khóa with}:
// Static import
import config from './config.json' with { type: 'json' };
// Dynamic import
const data = await import('./data.json', { with: { type: 'json' } });
console.log(config.version);
The with { type: 'json' } attribute tells the runtime how to parse and validate the module {Attribute with { type: 'json' } báo cho runtime cách parse và validate module}. This is a security feature too — the runtime won’t execute a .json URL as JavaScript {Đây cũng là tính năng bảo mật — runtime sẽ không thực thi một URL .json như JavaScript}. JSON is the first supported type; more will follow {JSON là type đầu tiên được hỗ trợ; sẽ có thêm sau}.
Float16Array — Half-Precision Floats {Float16Array — Số thực nửa độ chính xác}
A new typed array for 16-bit floats, useful for GPU/ML workloads, graphics, and bandwidth-sensitive data {Một typed array mới cho số thực 16-bit, hữu ích cho GPU/ML, đồ họa, và dữ liệu nhạy băng thông}.
const floats = new Float16Array([1.5, 2.25, 3.125]);
console.log(floats[0]); // 1.5 (stored in 2 bytes instead of 4 or 8)
// Companion APIs:
const view = new DataView(new ArrayBuffer(2));
view.setFloat16(0, 3.14);
view.getFloat16(0); // ~3.14 (rounded to half precision)
Math.f16round(3.14159); // nearest value representable as a float16
Half precision trades accuracy for half the memory of Float32Array — a common tradeoff in machine learning tensors {Nửa độ chính xác đánh đổi độ chính xác lấy một nửa bộ nhớ so với Float32Array — đánh đổi phổ biến trong tensor học máy}.
Part 2 — ECMAScript 2026 {Phần 2 — ECMAScript 2026}
These reached Stage 4 and ship in current engines; they’re slated for the ES2026 edition (≈ June 2026) {Những thứ này đã đạt Stage 4 và có trong các engine hiện tại; dự kiến vào phiên bản ES2026 (≈ tháng 6/2026)}.
Explicit Resource Management — using & await using {Quản lý tài nguyên tường minh — using & await using}
The headline of ES2026 {Tính năng đinh của ES2026}. The new using declaration automatically disposes a resource when it goes out of scope — like a destructor, or Python’s with, or C#‘s using {Khai báo using mới tự động dọn dẹp tài nguyên khi ra khỏi scope — như destructor, như with của Python, hay using của C#}.
A disposable resource defines a [Symbol.dispose]() method {Một tài nguyên disposable định nghĩa phương thức [Symbol.dispose]()}:
function openFile(path) {
const handle = acquireHandle(path);
return {
handle,
read() { return readFrom(this.handle); },
[Symbol.dispose]() {
releaseHandle(handle); // runs automatically at scope exit
},
};
}
function process() {
using file = openFile('/tmp/data');
const text = file.read();
return text.toUpperCase();
// No try/finally needed — file[Symbol.dispose]() runs here,
// even if an error is thrown above.
}
For async resources (network connections, async DB handles), use await using with [Symbol.asyncDispose]() {Với tài nguyên bất đồng bộ (kết nối mạng, handle DB async), dùng await using với [Symbol.asyncDispose]()}:
async function query() {
await using conn = await db.connect(); // has [Symbol.asyncDispose]
return conn.run('SELECT 1');
// await conn[Symbol.asyncDispose]() runs (and is awaited) on exit.
}
Supporting pieces {Các mảnh hỗ trợ}:
DisposableStack/AsyncDisposableStack— containers to aggregate multiple resources and dispose them all together (in reverse order) {container gom nhiều tài nguyên và dọn tất cả cùng lúc (theo thứ tự ngược)}.SuppressedError— when a cleanup throws while another error is already propagating, both are preserved (the new one as.error, the original as.suppressed) {khi việc dọn dẹp throw trong lúc một lỗi khác đang lan, cả hai được giữ lại}.
Constraint {Ràng buộc}:
using/await usingare block-scoped only — inside{}, loops, or function bodies — not at the top level of a module {using/await usingchỉ trong block — bên trong{}, vòng lặp, hay thân hàm — không dùng ở top-level của module}.
This replaces the error-prone try { ... } finally { cleanup() } dance for any resource with a lifecycle {Nó thay thế điệu nhảy dễ sai try { ... } finally { cleanup() } cho mọi tài nguyên có vòng đời}.
Array.fromAsync — Array.from for Async Iterables {Array.fromAsync — Array.from cho async iterable}
Array.from doesn’t understand async iterables {Array.from không hiểu async iterable}. Array.fromAsync does — it awaits each value and collects them {Array.fromAsync thì có — nó await từng giá trị rồi gom lại}.
async function* fetchPages() {
yield await fetch('/api/page/1').then((r) => r.json());
yield await fetch('/api/page/2').then((r) => r.json());
}
// await each yielded value, build an array
const pages = await Array.fromAsync(fetchPages());
console.log(pages.length); // 2
// also works on an array of promises:
const data = await Array.fromAsync([fetch('/a'), fetch('/b')]);
It’s the missing async counterpart to Array.from, and it processes values sequentially (unlike Promise.all, which is parallel) {Đây là phiên bản async còn thiếu của Array.from, và xử lý giá trị tuần tự (khác Promise.all vốn song song)}.
Error.isError — Reliable Error Detection {Error.isError — Phát hiện Error đáng tin}
value instanceof Error lies across realms (iframes, worker threads, vm contexts) and can be fooled by fake prototypes {value instanceof Error nói dối khi qua realm (iframe, worker, vm context) và có thể bị lừa bằng prototype giả}. Error.isError() checks the real internal brand {Error.isError() kiểm tra “nhãn” nội bộ thật sự}.
Error.isError(new Error('x')); // true
Error.isError(new TypeError('y')); // true
// Cases where instanceof fails but isError is correct:
Error.isError({ name: 'Error', message: 'fake' }); // false (just an object)
// An Error from another iframe/realm:
Error.isError(errorFromIframe); // true (instanceof would be false)
Reach for it in libraries, error-normalization layers, and anywhere errors may cross context boundaries {Dùng nó trong thư viện, lớp chuẩn hóa lỗi, và bất kỳ đâu lỗi có thể vượt ranh giới context}.
How to Use These Today {Cách dùng ngay hôm nay}
- Check support {Kiểm tra hỗ trợ}: most ES2025 features are already in current Chrome, Firefox, Safari, Node, Deno, and Bun {phần lớn tính năng ES2025 đã có trong Chrome, Firefox, Safari, Node, Deno, Bun bản hiện tại}. ES2026 items (
using,Array.fromAsync,Error.isError) are shipping but check your minimum target {các mục ES2026 đang được tung ra nhưng hãy kiểm tra target tối thiểu của bạn}. - Transpile {Transpile}: TypeScript 5.2+ supports
using/await using; Babel and@babel/preset-envdown-level most syntax {TypeScript 5.2+ hỗ trợusing/await using; Babel hạ cấp được phần lớn cú pháp}. - Polyfill {Polyfill}:
core-jscovers Iterator Helpers, Set methods,Promise.try,Array.fromAsync, and more for older runtimes {core-jsbao gồm Iterator Helpers, Set methods,Promise.try,Array.fromAsync,… cho runtime cũ}.
Quick Reference {Tham chiếu nhanh}
| Feature {Tính năng} | Edition | One-liner {Tóm tắt} |
|---|---|---|
| Iterator Helpers | ES2025 | Lazy .map/.filter/.take on iterators |
| Set methods | ES2025 | union / intersection / difference / … |
Promise.try | ES2025 | Sync + async errors in one chain |
RegExp.escape | ES2025 | Escape strings for dynamic regex |
| Regex inline flags | ES2025 | (?i:...) per-group modifiers |
| Import attributes | ES2025 | import x from './a.json' with { type: 'json' } |
Float16Array | ES2025 | Half-precision typed array |
using / await using | ES2026 | Auto-dispose resources at scope exit |
Array.fromAsync | ES2026 | Array.from for async iterables |
Error.isError | ES2026 | Realm-safe Error check |
JavaScript keeps absorbing the patterns we used to pull from libraries — lazy iteration, set algebra, safe regex building, deterministic cleanup {JavaScript tiếp tục hấp thụ những mẫu mà ta từng phải lấy từ thư viện — lặp lười, đại số tập hợp, dựng regex an toàn, dọn dẹp xác định}. The fewer dependencies for these basics, the better {Càng ít dependency cho những thứ cơ bản này càng tốt}.
Related {Liên quan}: JavaScript Generators & yield · Unicode, Strings & Binary in JavaScript.