Trong JavaScript, biến không có kiểu (untyped) – biến chỉ là tên tham chiếu. Giá trị mới có kiểu. Cùng một biến có thể giữ các giá trị kiểu khác nhau tại các thời điểm khác nhau.
Minh họa: Biến thay đổi kiểu giá trị
let a; // undefined
console.log(typeof a); // "undefined"
a = true; // boolean
console.log(typeof a); // "boolean"
a = 5; // number
console.log(typeof a); // "number"
a = "web"; // string
console.log(typeof a); // "string"
a = { key: "value" }; // object
console.log(typeof a); // "object"
a = [1, 2, 3]; // array (object)
console.log(typeof a); // "object"
a = () => {}; // function (object)
console.log(typeof a); // "function"
Ví dụ từ bài gốc (đã hiện đại hóa)
<!DOCTYPE html>
<html>
<body>
<pre id="output"></pre>
<script>
let a;
const log = (msg) => document.getElementById('output').textContent += msg + '\n';
log('typeof a: ' + typeof a); // "undefined"
a = true;
log('typeof a: ' + typeof a); // "boolean"
a = 5;
log('typeof a: ' + typeof a); // "number"
a = "web";
log('typeof a: ' + typeof a); // "string"
</script>
</body>
</html>
Cơ chế lưu trữ
- Primitive (string, number, boolean, null, undefined, symbol, bigint): Giá trị lưu trực tiếp trong biến (stack). Gán cho biến khác → copy giá trị.
- Object (object, array, function, date, regex...): Biến lưu tham chiếu (reference) đến object trong heap. Gán cho biến khác → copy tham chiếu (cùng trỏ 1 object).
// Primitive: Copy giá trị
let x = 10;
let y = x;
y = 20;
console.log(x); // 10 (không đổi)
// Object: Copy tham chiếu
let obj1 = { value: 10 };
let obj2 = obj1;
obj2.value = 20;
console.log(obj1.value); // 20! (cùng object)
Thay đổi nội dung vs Gán lại biến
| Hành động | Primitive | Object |
|---|---|---|
Gán lại biến (x = newVal) | Tạo giá trị mới, biến trỏ giá trị mới | Biến trỏ object mới, object cũ có thể bị GC |
| Sửa đổi nội dung | ❌ Không thể (immutable) | ✅ Có thể (obj.prop = val, arr.push()) |
Kiểm tra kiểu tại runtime
function checkType(val) {
console.log(`Value: ${val}, Type: ${typeof val}, isArray: ${Array.isArray(val)}`);
}
checkType(42); // number
checkType("hello"); // string
checkType(true); // boolean
checkType(null); // object (bug)
checkType(undefined); // undefined
checkType({}); // object
checkType([]); // object (Array.isArray = true)
checkType(() => {}); // function
checkType(Symbol()); // symbol
checkType(123n); // bigint
Best Practice
- Dùng
constmặc định – biến không trỏ sang object khác (nhưng object nội bộ vẫn sửa được). - Cẩn thận khi copy object – dùng spread
{...obj}hoặcstructuredClone()nếu cần bản sao độc lập. - Dùng TypeScript nếu muốn kiểm tra kiểu tĩnh.