JavaScript Data Types: Hiểu Để Không Bị "Type Coercion" Điều Khiển
Khi lập trình JavaScript, chắc chắn bạn đã từng gặp những trường hợp "dở khóc dở cười" khi so sánh các giá trị. JavaScript không phải là một ngôn ngữ "strictly typed", chính vì thế việc hiểu rõ từ undefined đến Symbol sẽ giúp bạn tránh được những bug "ngớ ngẩn" mà 99% lập trình viên đều từng mắc phải.
1. Có bao nhiêu kiểu dữ liệu trong JavaScript?
JavaScript phân loại các kiểu dữ liệu thành hai nhóm chính:
1.1 Primitive types (Kiểu nguyên thủy)
Đây là các kiểu dữ liệu cơ bản, được lưu trữ trực tiếp trong Stack:
undefinednullbooleannumberstringbigint(ES2020)symbol(ES6)
1.2 Non-primitive types (Kiểu tham chiếu)
Chỉ có một kiểu non-primitive duy nhất là Object, nhưng nó bao gồm:
- Object literal:
{ } - Array:
[ ] - Function:
function() { } - Date, RegExp, v.v.
Tip: Bạn có thể kiểm tra kiểu giá trị bằng toán tửtypeof. Tuy nhiên,typeof null === 'object'là một bug "huyền thoại" tồn tại từ thuở sơ khai của JavaScript mà bạn cần lưu ý.
2. typeof — Đừng quá tin tưởng
typeof null//"object"← Bug kinh điểntypeof NaN//"number"← Số nhưng lại là "Not a Number"typeof []//"object"← Không phân biệt được với object thườngtypeof (() => {})//"function"← OK
Lời khuyên: Để kiểm tra Array, hãy dùng Array.isArray(value) thay vì typeof.
3. Sự khác biệt giữa undefined và null
let a;(Khai báo nhưng chưa gán giá trị) →alàundefined.let b = null;(Chủ động gán giá trị "trống") →blànull.
Bug thường gặp: So sánh bằng toán tử == giữa null và undefined trả về true, nhưng === thì không.
JavaScript
null == undefined // true
null === undefined // false
4. So sánh == vs === — "Kẻ hủy diệt" hệ thống
Việc ép kiểu tự động (coercion) của JavaScript khi dùng == có thể dẫn tới những kết quả không tưởng:
0 == false//true"" == false//true[] == false//true[] == ![]//true← 🤔???
Lời khuyên: Luôn luôn sử dụng === để tránh những kết quả kỳ lạ do việc ép kiểu tự động gây ra.
5. Symbol và BigInt — Những "người lạ" ít dùng
Symbol
Tạo ra một định danh duy nhất (unique) và không thể trùng lặp.
JavaScript
const id1 = Symbol('id');
const id2 = Symbol('id');
console.log(id1 === id2); // false
- Use case: Tạo các key ẩn cho object hoặc enum an toàn, tránh xung đột tên.
BigInt
Dùng cho các số nguyên cực lớn vượt quá giới hạn an toàn của Number.
JavaScript
const max = BigInt(Number.MAX_SAFE_INTEGER);
console.log(max + 1n); // Hoạt động tốt
// Lưu ý: Không thể trộn lẫn BigInt với Number thường
// 123 + 1n → Error!
6. Các lỗi kinh điển trong thực tế
1. Object vs Array
Cả hai đều trả về "object" khi dùng typeof.
- Bug thường gặp: Xử lý Array như một Object (hoặc ngược lại) khi thực hiện deep clone hoặc vòng lặp.
2. Falsy values
Các giá trị được coi là false trong câu lệnh điều kiện: false, 0, "", null, undefined, NaN.
JavaScript
const values = [false, 0, "", null, undefined, NaN];
values.forEach(v => {
if (!v) {
console.log(`"${v}" là falsy`);
}
});
Tip: Nếu bạn cần kiểm tra chính xác null hoặc undefined, đừng dùng if (!value), hãy dùng value === null || value === undefined.
7. JSON và những cái bẫy
Dữ liệu có thể bị mất mát khi bạn dùng JSON.stringify():
JSON.stringify(undefined)//undefinedJSON.stringify({ a: undefined })//"{}"(Key 'a' biến mất)JSON.stringify([undefined])//"[null]"(Chuyển thành null)
Lưu ý: undefined không thể được stringify hoàn chỉnh, điều này dễ dẫn đến mất dữ liệu khi gửi POST API.
8. Tổng kết kinh nghiệm
- Dùng
typeofcho các kiểu nguyên thủy (string,number,boolean,...). - Dùng
Array.isArray()cho Array. - Tránh dùng
typeof null,typeof [],typeof NaN. - Dùng
== nullnếu muốn bắt cảnullvàundefined. - Luôn dùng
===để so sánh giá trị.
JavaScript không bắt lỗi kiểu dữ liệu lúc viết code, nhưng nó rất dễ làm ứng dụng của bạn "bay màu" chỉ vì một lỗi ép kiểu vô tình. Kiểm soát được kiểu dữ liệu là bạn đã kiểm soát được 50% độ ổn định của ứng dụng.
Cảm ơn bạn đã đọc bài viết! Hãy luôn hoài nghi mọi phép so sánh trong JavaScript nhé.