ES13 Interactive Hub — ECMAScript 2022
Top-level await, class fields (private + static), Array.at() negative index, Error cause, Object.hasOwn, class static blocks, ergonomic brand check (#field in obj) — thêm tính năng class + cải thiện DX.
Top-level await
Chuyên đề cốt lõi
💡 Khái niệm tóm tắt
Sử dụng await trực tiếp ở module level — không cần bọc trong hàm async. CHỈ hợp lệ trong ES module.
🤔 Tại sao cần tính năng này?
Trước ES13, muốn await ở top-level phải bọc trong IIFE async — rườm rà. Đặc biệt khi cần khởi tạo dữ liệu async trước khi export. Top-level await giúp module có thể đợi tài nguyên trước khi sẵn sàng.
// Trước ES13 — phải bọc IIFE async
// file: config.mjs
let config;
(async () => {
const res = await fetch('/api/config');
config = await res.json();
})();
export { config }; // có thể chưa load xong!
// Hoặc export Promise
export const configPromise = fetch('/api/config').then(r => r.json());// ES13 — top-level await trong ES module
// file: config.mjs
const res = await fetch('/api/config');
export const config = await res.json();
// File khác import — module này sẽ đợi xong rồi mới chạy
// import { config } from './config.mjs';
// console.log(config); // đã có data sẵn
// Conditional dynamic import ở top-level
const lang = navigator.language.startsWith('vi') ? 'vi' : 'en';
const { messages } = await import(`./locales/${lang}.js`);
export { messages };Bảng Tra Cứu Nhanh ES13
Xem nhanh cấu trúc + copy snippet
Sử dụng await trực tiếp ở module level — không cần bọc trong hàm async. CHỈ hợp lệ trong ES module.
const res = await fetch('/api/config');
export const config = await res.json();
const lang = navigator.language.startsWith('vi') ? 'vi' : 'en';
...Khai báo field private thật sự bằng prefix "#" — browser enforce, không thể truy cập từ bên ngoài class.
class User {
name = ''; // public field
#password = ''; // private field
...Truy cập phần tử bằng index, hỗ trợ index ÂM để đếm từ cuối — sạch hơn arr[arr.length - 1].
const arr = [10, 20, 30, 40, 50]; console.log(arr.at(-1)); // 50 (cuối) console.log(arr.at(-2)); // 40 ...
Tham số { cause } khi tạo Error giữ lại lỗi nguyên nhân — hữu ích khi rethrow ở tầng cao hơn để giữ context.
async function loadDashboard() {
try {
await fetchUser();
...Thay thế ngắn gọn và an toàn cho "Object.prototype.hasOwnProperty.call(obj, key)" — kiểm tra property thuộc về object hay là kế thừa.
const obj = { name: "Lan" };
console.log(Object.hasOwn(obj, 'name')); // true
console.log(Object.hasOwn(obj, 'toString')); // false (inherited)
...Block "static { ... }" chạy MỘT LẦN ngay khi class được định nghĩa — dùng để init logic phức tạp cho static state (try/catch, truy cập private field, tính toán).
class Logger {
static instances = [];
static defaultLevel;
...Toán tử "in" mở rộng cho phép kiểm tra object có private field hay không bằng cú pháp "#field in obj" — KHÔNG throw lỗi như khi truy cập trực tiếp.
class Point {
#x;
#y;
...