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).
Chu kỳ phát hành hàng năm
Từ ES2016, TC39 phát hành một phiên bản ECMAScript mới mỗi tháng Sáu. Một proposal trở thành một phần của ngôn ngữ khi đạt Stage 4.
- ES2025 (phiên bản thứ 16) được chốt vào 25/06/2025.
- ES2026 đang trên đà được duyệt vào khoảng tháng 6/2026; các tính năng dưới đây đã đạt Stage 4 và có mặt trong các engine hiện đại.
Đây là chuyến đi thực hành — mỗi tính năng đều có ví dụ chạy được.
Ghi chú tên gọi: ""ESxxxx” chỉ năm spec được xuất bản, không phải khi engine triển khai. 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.
Phần 1 — ECMAScript 2025
Iterator Helpers — Phương thức kiểu Array nhưng lười
Cải thiện trải nghiệm lớn nhất trong ES2025. 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]
Tại sao quan trọng: với array, [...infinite].map().filter() sẽ treo mãi vì mỗi bước dựng một array trung gian đầy đủ. 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.
Các helper có sẵn: map, filter, flatMap, take, drop, reduce, toArray, forEach, some, every, find, 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 — Đại số tập hợp thật sự
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)
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. Không còn phải viết new Set([...a].filter(x => b.has(x))).
Promise.try — Bắt đầu chuỗi một cách an toàn
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
Đâ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 — Pattern động an toàn
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() 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: Cờ inline + nhóm tên trùng
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)
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
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);
Attribute with { type: 'json' } báo cho runtime cách parse và validate module. Đâ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 là type đầu tiên được hỗ trợ; sẽ có thêm sau.
Float16Array — Số thực nửa độ chính xác
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
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.
Phần 2 — ECMAScript 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).
Quản lý tài nguyên tường minh — using & await using
Tính năng đinh của ES2026. 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#.
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.
}
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.
}
Các mảnh hỗ trợ:
- container gom nhiều tài nguyên và dọn tất cả cùng lúc (theo thứ tự ngược).
- 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.
Ràng buộc:
using/await usingusing/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.
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 cho async iterable
Array.from không hiểu async iterable. 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')]);
Đâ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 — Phát hiện Error đáng tin
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() 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)
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.
Cách dùng ngay hôm nay
- Kiểm tra hỗ trợ: phần lớn tính năng ES2025 đã có trong Chrome, Firefox, Safari, Node, Deno, Bun bản hiện tại. 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: TypeScript 5.2+ hỗ trợ
using/await using; Babel hạ cấp được phần lớn cú pháp. - Polyfill:
core-jsbao gồm Iterator Helpers, Set methods,Promise.try,Array.fromAsync,… cho runtime cũ.
Tham chiếu nhanh
| Tính năng | Edition | 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 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. Càng ít dependency cho những thứ cơ bản này càng tốt.
Liên quan: