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

JavaScript typeof: vì sao kiểm tra biến vẫn ném ReferenceError?

Thêm typeof để kiểm tra biến nhưng chương trình vẫn dừng với ReferenceError. typeof xử lý được một tên chưa được khai báo, nhưng không cho phép đọc binding let hoặc const đang chờ khởi tạo. Khác biệt này thường lộ ra sau khi chuyển mã vào một block hoặc thêm biến cục bộ cùng tên.

JavaScript typeof: vì sao kiểm tra biến vẫn ném ReferenceError?

Thêm typeof để kiểm tra biến nhưng chương trình vẫn dừng với ReferenceError. typeof xử lý được một tên chưa được khai báo, nhưng không cho phép đọc binding let hoặc const đang chờ khởi tạo. Khác biệt này thường lộ ra sau khi chuyển mã vào một block hoặc thêm biến cục bộ cùng tên.

1. Không khai báo khác với đã khởi tạo bằng undefined

console.log(typeof htvMissingNameForExample); // undefined
let ready;
console.log(typeof ready); // undefined
console.log(ready === undefined); // true

Ví dụ giả định htvMissingNameForExample không tồn tại trong môi trường chạy. Hai phép typeof cho cùng chuỗi 'undefined', nhưng ready đã có binding hợp lệ và đọc được trực tiếp. Biến let không có giá trị gán sẽ được khởi tạo bằng undefined khi luồng thực thi tới khai báo.

2. Trước khi khai báo chạy, typeof vẫn có thể ném lỗi

{
  try {
    console.log(typeof count);
  } catch (error) {
    console.log(error instanceof ReferenceError); // true
  }
  let count = 1;
  console.log(typeof count); // number
}

Binding count thuộc block đã được xác lập, nhưng chưa được khởi tạo ở thời điểm đọc đầu tiên. Khoảng thời gian đó thường gọi là temporal dead zone, viết tắt TDZ. typeof không bỏ qua trạng thái chưa khởi tạo này.

Đừng thay let bằng var chỉ để che triệu chứng. Xem lại thứ tự thực thi và đặt bước tạo dữ liệu trước nơi sử dụng. Với const, cũng phải chờ khai báo được thực thi; const còn yêu cầu giá trị khởi tạo ngay trong khai báo.

3. Biến cục bộ có thể che biến ngoài từ đầu block

const limit = 10;
{
  try {
    console.log(limit);
  } catch (error) {
    console.log(error instanceof ReferenceError); // true
  }
  const limit = 20;
  console.log(limit); // 20
}
console.log(limit); // 10

Trong block, tên limit trỏ tới binding cục bộ đang ở TDZ, không quay ra lấy 10 ở ngoài. Sau khai báo, giá trị cục bộ là 20. Khi ra khỏi block, tên đó lại tham chiếu tới biến ngoài.

Ví dụ tự kiểm chứng lý do một đoạn log đang chạy có thể lỗi ngay sau khi thêm const cùng tên ở phía dưới. Nếu hai biến mang ý nghĩa khác nhau, đặt tên thể hiện khác biệt giúp người đọc tránh suy luận nhầm phạm vi.

4. Tham số mặc định cũng có thứ tự khởi tạo

function combine(first = second, second = 2) {
  return first + second;
}
try {
  combine(undefined, 3);
} catch (error) {
  console.log(error instanceof ReferenceError); // true
}
console.log(combine(1, 3)); // 4
function copyDefault(first = 2, second = first) {
  return first + second;
}
console.log(copyDefault()); // 4

Tham số được khởi tạo theo thứ tự từ trái sang phải. Khi biểu thức mặc định của first đọc second, binding second chưa sẵn sàng, dù lời gọi đã truyền 3 ở vị trí thứ hai. Truyền first bằng 1 bỏ qua biểu thức mặc định đó nên lời gọi tiếp theo chạy được.

copyDefault minh họa hướng phụ thuộc thuận: giá trị mặc định phía sau đọc tham số đã khởi tạo phía trước. Đây là ví dụ về thứ tự, không phải một hàm kiểm tra kiểu số. Với API thực tế, vẫn cần validation riêng.

5. Cách tìm lỗi trong mã ứng dụng

  • Xác định chính xác binding mà tên biến đang trỏ tới.
  • Tìm let hoặc const cùng tên trong block gần nhất.
  • Kiểm tra đường chạy có đọc biến trước khai báo không.
  • Xem biểu thức mặc định có phụ thuộc tham số phía sau không.
  • Kiểm thử luồng truyền undefined, không chỉ luồng truyền đủ giá trị.

Tám khối ví dụ Việt–Anh đã chạy bằng Node.js, kèm kiểm tra let, const và tham số mặc định. Không kiểm thử vòng phụ thuộc module hoặc ứng dụng trình duyệt. Tham khảo MDN typeof, let và default parameters.

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.