JavaScript · ES2022

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.

Kinh Nghiệm
0 XP
Hoàn thành khóa học0%

Top-level await

Chuyên đề cốt lõi

Khó6 phút

💡 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 (cách viết cũ)Verbose / Cồng kềnh
// 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 (Hiện đại)Tối ưu & Khuyên dùng
// 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ạn đã nắm chắc? Thử chạy code thật hoặc làm trắc nghiệm!

Bảng Tra Cứu Nhanh ES13

Xem nhanh cấu trúc + copy snippet

Top-level await

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';
...
Class Private Fields (#)

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
...
Array.at() & String.at()

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
...
Error cause

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();
...
Object.hasOwn()

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)
...
Class static blocks

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;
...
Ergonomic brand check (#field in obj)

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;
...