Hiểu rõ các type trong JavaScript: Thực tế, lỗi phổ biến và mẹo "sống còn"
Một bài viết thực chiến về type trong JavaScript – từundefined
tớiSymbol
, đi kèm các tips giúp bạn tránh bug "ngớ ngẩn" mà 99% dev từng mắc phải.
1. Có bao nhiêu kiểu dữ liệu (type) trong JavaScript?
JavaScript phân loại type thành hai nhóm chính:
1.1 Primitive types
Đây là các kiểu dữ liệu nguyên thủy, được lưu trực tiếp trong stack:
undefined
null
boolean
number
string
bigint
(ES2020)symbol
(ES6)
1.2 Non-primitive types
Chỉ có duy nhất 1 kiểu non-primitive: object
, bao gồm:
- object literal:
{ }
- array:
[ ]
- function:
function() { }
(thực ra function cũng là object) - date, regexp, v.v.
Tip: Bạn có thể kiểm tra loại giá trị bằngtypeof
, nhưngtypeof null === 'object'
là một bug đã có từ rất lâu trong lịch sử của javascript
2. typeof
— đừng tin tưởng
typeof null // "object" ← bug thiết kế
typeof NaN // "number" ← ???
typeof [] // "object" ← không rõ là array
typeof (() => {}) // "function" ← OK, đặc biệt dành riêng cho function
Tip: Để kiểm tra array, dùngArray.isArray(value)
thay vìtypeof
.
3. Sự khác biệt giữa undefined
và null
undefined | null |
---|---|
Biến chưa được gán giá trị | Được gán rõ ràng để thể hiện “không có giá trị” |
Do trình thông dịch tự gán | Do lập trình viên gán |
let a;
console.log(a); // undefined
let b = null;
console.log(b); // null
Bug phổ biến: So sánh==
giữanull
vàundefined
trả vềtrue
, nhưng===
thì không
null == undefined // true
null === undefined // false
4. So sánh bằng ==
vs ===
– kẻ hủy diệt hệ thống
0 == false // true
"" == false // true
[] == false // true
[] == ![] // true ← ????
null == undefined // true
Lời khuyên sống còn: Luôn dùng ===
để tránh các kết quả kỳ lạ do coercion (ép kiểu ngầm).
5. symbol
và bigint
— những kẻ xa lạ (ít ai dùng)
Symbol
– kiểu dữ liệu duy nhất luôn khác biệt
const id1 = Symbol('id');
const id2 = Symbol('id');
console.log(id1 === id2); // false
Use cases: tạo các khóa không bị xung đột trong object hoặc enum an toàn.
BigInt
– cho số rất lớn
const max = BigInt(Number.MAX_SAFE_INTEGER);
console.log(max + 1n); // hoạt động ổn
// Chú ý: Không thể mix với number
`123 + 1n // Error!
6. Một vài lỗi type kinh điển trong thực tế
1. Object vs Array
typeof {} // "object"
typeof [] // "object"
Array.isArray([]) // true
Bug phổ biến: xử lý array như object hoặc ngược lại khi làm deep clone, loop, etc.
2. Falsy value
const values = [false, 0, "", null, undefined, NaN];
values.forEach(v => {
if (!v) {
console.log(`"${v}" là falsy`);
}
});
Tip: Nếu cần kiểm tra chính xác null hoặc undefined, đừng dùngif (!value)
mà hãyvalue === null || value === undefined
.
7. Mẹo sử dụng typeof
, instanceof
, constructor
Method | Dùng cho | Giới hạn |
---|---|---|
typeof | Kiểu primitive | Không phân biệt object/array/function |
instanceof | Object cụ thể | Không dùng được với primitive |
.constructor | Xác định class | Không an toàn khi object bị prototype chain thay đổi |
Ví dụ:
[] instanceof Array // true
({}) instanceof Object // true
({}).constructor === Object // true
8. JSON và sự thật mất lòng
JSON.stringify(undefined) // undefined
JSON.stringify({ a: undefined }) // "{}"
JSON.stringify([undefined]) // "[null]"
Lưu ý: undefined
không được stringify → dễ mất dữ liệu khi POST API
9. Khi nào nên dùng typeof
, khi nào không?
- Dùng
typeof
cho primitive (number
,string
,boolean
, etc.) - Dùng
Array.isArray()
cho array - Tránh
typeof null
,typeof []
,typeof NaN
- Dùng
== null
để bắt cảnull
lẫnundefined
→ nhanh nhưng không rõ ràng - Ưu tiên
===
để tránh coercion
10. Kết luận
JavaScript không phải ngôn ngữ “strict type” nhưng lại cực kỳ dễ dính bug vì ép kiểu ngầm. Việc hiểu rõ bản chất các type, hạn chế của typeof
, ==
, ===
, null
, undefined
sẽ giúp bạn:
- Tránh bug khó debug
- Viết code rõ ràng, dễ maintain
- Giảm thời gian QA fix lỗi "vặt vãnh"
Hãy “nghi ngờ” mọi phép so sánh trong JavaScript. Nếu bạn không kiểm soát type, type sẽ kiểm soát bạn.