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

Optional chaining trong JavaScript: vì sao thêm ?. mà vẫn báo lỗi?

Đã thêm ?. nhưng dòng đọc dữ liệu vẫn ném TypeError. Optional chaining giúp xử lý một tham chiếu có thể là null hoặc undefined, nhưng hiệu quả phụ thuộc vị trí đặt toán tử và việc chuỗi truy cập còn liên tục hay không. Bài viết dùng những ví dụ nhỏ để xác định ranh giới đó trước khi sửa mã giao diện.

Optional chaining trong JavaScript: vì sao thêm ?. mà vẫn báo lỗi?

Đã thêm ?. nhưng dòng đọc dữ liệu vẫn ném TypeError. Optional chaining giúp xử lý một tham chiếu có thể là null hoặc undefined, nhưng hiệu quả phụ thuộc vị trí đặt toán tử và việc chuỗi truy cập còn liên tục hay không. Bài viết dùng những ví dụ nhỏ để xác định ranh giới đó trước khi sửa mã giao diện.

1. Dấu ngoặc có thể kết thúc chuỗi được bảo vệ

const user = null;
console.log(user?.profile.name); // undefined
try {
  console.log((user?.profile).name);
} catch (error) {
  console.log(error instanceof TypeError); // true
}

Ở biểu thức đầu, user là null nên phần còn lại của chuỗi liên tục không được đánh giá. Ở biểu thức sau, kết quả user?.profile là undefined; thao tác .name bên ngoài ngoặc vẫn chạy và gây lỗi.

Khi tách một chuỗi thành biến trung gian trong lúc refactor, hãy kiểm tra lại điểm có thể thiếu dữ liệu. Việc đổi cách viết có thể đổi hành vi dù các tên thuộc tính vẫn giống nhau.

2. Mỗi tầng tùy chọn cần được thể hiện rõ

const user = {};
try {
  console.log(user?.profile.name);
} catch (error) {
  console.log(error instanceof TypeError); // true
}
console.log(user?.profile?.name); // undefined
console.log(user?.profile?.name ?? 'Anonymous'); // Anonymous

user tồn tại nên dấu ?. đầu tiên không dừng chuỗi. profile lại là undefined, khiến .name thông thường thất bại. Nếu profile cũng là trường tùy chọn theo hợp đồng, đặt ?. tại tầng đó.

Không thêm ?. vào mọi vị trí chỉ để màn hình hết lỗi. Một trường bắt buộc bị mất có thể là lỗi API cần phát hiện. Giá trị thay thế Anonymous trong ví dụ chỉ hợp lý nếu sản phẩm cho phép hồ sơ không có tên.

3. Gọi tùy chọn không xác nhận giá trị là hàm

console.log(({}).onReady?.()); // undefined
const widget = { onReady: 'ready' };
try {
  widget.onReady?.();
} catch (error) {
  console.log(error instanceof TypeError); // true
}
const service = { label: 'ready', onReady() { return this.label; } };
console.log(service.onReady?.()); // ready

Thuộc tính không có giá trị thì lời gọi tùy chọn có thể trả undefined. Thuộc tính chứa chuỗi vẫn không thể gọi được. Ví dụ service cũng cho thấy lời gọi trực tiếp qua object giữ ngữ cảnh this; nếu lấy method ra biến riêng, cần xem lại cách method dùng this.

Với callback từ cấu hình không đáng tin cậy, kiểm tra typeof callback === 'function' khi hợp đồng yêu cầu, hoặc báo lỗi cấu hình. Optional chaining không thay thế kiểm tra kiểu.

4. Biểu thức bị bỏ qua không thực hiện tác dụng phụ

const rows = null;
let index = 0;
console.log(rows?.[index++]); // undefined
console.log(index); // 0
let calls = 0;
const callback = undefined;
callback?.(++calls);
console.log(calls); // 0

Các ví dụ tự kiểm chứng rằng tăng index và tăng calls không diễn ra khi chuỗi dừng sớm. Không đặt công việc bắt buộc, như ghi nhận một bước xử lý, bên trong biểu thức chỉ chạy khi dữ liệu tùy chọn tồn tại. Tách nó thành câu lệnh riêng nếu cần chạy trong mọi trường hợp.

5. Review hợp đồng trước khi rút gọn mã

  • Xác định trường nào được phép thiếu và trường nào bắt buộc.
  • Thử null ở gốc và undefined ở tầng trung gian riêng biệt.
  • Kiểm tra dấu ngoặc hoặc biến tạm có làm đứt chuỗi không.
  • Thử callback bị thiếu và callback sai kiểu.
  • Xác nhận công việc bắt buộc không bị bỏ qua do dừng sớm.

Tám khối ví dụ Việt–Anh đã chạy bằng Node.js, kèm kiểm tra ma trận trường hợp thiếu dữ liệu và lời gọi method. Chưa kiểm thử tích hợp component trình duyệt. Tham khảo MDN Optional chaining và đặc tả ECMAScript về optional chains.

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.