Lập trình · 20/10/2026

Destructuring trong JavaScript: vì sao có mặc định mà vẫn lỗi với null?

Hàm đã viết tham số mặc định bằng {} nhưng vẫn báo lỗi khi API gửi null. Destructuring giúp lấy dữ liệu ngắn gọn, song mỗi giá trị mặc định chỉ xử lý đúng vị trí được khai báo. Ví dụ dưới đây phân biệt mặc định của tham số, thuộc tính và object lồng nhau.

Destructuring trong JavaScript: vì sao có mặc định mà vẫn lỗi với null?

Hàm đã viết tham số mặc định bằng {} nhưng vẫn báo lỗi khi API gửi null. Destructuring giúp lấy dữ liệu ngắn gọn, song mỗi giá trị mặc định chỉ xử lý đúng vị trí được khai báo. Ví dụ dưới đây phân biệt mặc định của tham số, thuộc tính và object lồng nhau.

1. Đổi tên biến không đổi tên thuộc tính nguồn

const user = { display_name: 'Lan', settings: { compact: false } };
const { display_name: displayName, settings } = user;
settings.compact = true;
console.log(displayName); // Lan
console.log(user.display_name); // Lan
console.log(user.settings.compact); // true

display_name là khóa cần đọc; displayName là biến mới. Dòng khai báo không sửa tên khóa trong user. Biến settings vẫn trỏ tới object cũ, như ví dụ tự kiểm chứng qua thay đổi compact. Nếu component cần sửa dữ liệu độc lập, hãy tạo cấu trúc mới ở những tầng cần tách biệt.

2. Mặc định thuộc tính không thay thế null

const { label: a = 'Untitled' } = {};
const { label: b = 'Untitled' } = { label: undefined };
const { label: c = 'Untitled' } = { label: null };
console.log(a); // Untitled
console.log(b); // Untitled
console.log(c); // null

Giá trị mặc định được dùng khi kết quả đọc là undefined. null được giữ nguyên. Đây là quy tắc cú pháp, không phải quyết định thay ứng dụng về ý nghĩa dữ liệu trống. Nếu null mang nghĩa người dùng chủ động xóa nhãn, đổi nó thành nhãn mặc định có thể làm sai giao diện.

3. Mặc định ở tầng ngoài không bảo vệ mọi tầng

function readTheme({ settings: { theme = 'system' } = {} } = {}) {
  return theme;
}
console.log(readTheme()); // system
console.log(readTheme({})); // system
console.log(readTheme({ settings: {} })); // system
for (const input of [null, { settings: null }]) {
  try {
    readTheme(input);
  } catch (error) {
    console.log(error instanceof TypeError); // true
  }
}

Không truyền tham số sẽ kích hoạt = {} ở ngoài cùng. settings không tồn tại sẽ kích hoạt = {} ở tầng bên trong. Khi một trong hai vị trí nhận null, mặc định tương ứng không được dùng và việc tách thuộc tính thất bại.

Trước khi thêm nhiều tầng cú pháp, ghi rõ hợp đồng: null có được coi như thiếu cấu hình hay phải báo dữ liệu sai? Hai chính sách đều có thể phù hợp, nhưng cần nhất quán giữa client và API.

4. Chuẩn hóa từng tầng rồi mới lấy thuộc tính

Hàm minh họa dưới đây coi null và undefined ở cả hai tầng là thiếu cấu hình. Mảng và giá trị nguyên thủy bị từ chối. theme chỉ chấp nhận ba chuỗi đã định nghĩa; null ở riêng theme vẫn là lỗi. Hàm dành cho dữ liệu JSON thông thường, không phải bộ kiểm tra object tùy ý có getter hay prototype đặc biệt.

function parseTheme(input) {
  const options = input ?? {};
  if (typeof options !== 'object' || Array.isArray(options)) {
    throw new TypeError('Options object required');
  }
  const settings = options.settings ?? {};
  if (typeof settings !== 'object' || Array.isArray(settings)) {
    throw new TypeError('Settings object required');
  }
  const { theme = 'system' } = settings;
  if (!['system', 'light', 'dark'].includes(theme)) {
    throw new TypeError('Unsupported theme');
  }
  return theme;
}
console.log(parseTheme(null)); // system
console.log(parseTheme({ settings: null })); // system
console.log(parseTheme({ settings: { theme: 'dark' } })); // dark

Cách tách bước dài hơn một dòng destructuring nhưng chỉ rõ điểm chuẩn hóa và điểm validation. Không dùng ép kiểu để biến mọi đầu vào thành object hợp lệ: cấu hình sai cần xuất hiện thành lỗi có thể xử lý.

5. Những trường hợp nên giữ trong kiểm thử

  • Không truyền tham số, truyền undefined và truyền null.
  • Thiếu settings, settings bằng null, mảng hoặc chuỗi.
  • Thiếu theme, theme bằng null hoặc giá trị ngoài danh sách.
  • Đổi tên biến nhưng giữ nguyên khóa nguồn.
  • Sửa object được lấy ra và kiểm tra tác động tới nguồn.

Tám khối ví dụ Việt–Anh đã chạy bằng Node.js, kèm kiểm tra đầu vào sai cho parseTheme. Chưa kiểm thử tích hợp với API hay component trình duyệt. Quy tắc cú pháp được đối chiếu với MDN Destructuring và đặc tả ECMAScript về binding patterns.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.