← Lập trình JavaScript cơ bản

Bài 2 · Cơ bản · 20 phút· Cập nhật 11/06/2026

Biến & kiểu dữ liệu JavaScript

Biên soạn bởi Nguyễn Anh Tuấn

Biến let/const và kiểu dữ liệu JavaScript: number, string, boolean, null vs undefined; == vs === và ép kiểu (type coercion) - kèm bẫy float khi lưu tiền.

Biến là cái tên bạn đặt cho một giá trị. JavaScript hiện đại có hai cách khai báo: let (đổi được) và const (không gán lại). Cả hai đều block-scope - chỉ sống trong cặp { } chứa nó.

let đổi được · const không gán lại

let diem = 8;        // doi duoc
diem = 9;            // OK

const ten = "Lan";   // khong gan lai
// ten = "Hoa";      // TypeError: Assignment to constant variable

// const KHONG dong bang object - chi chan gan lai bien:
const sv = { ten: "Lan" };
sv.ten = "Hoa";      // OK (van sua duoc thuoc tinh)
  • Mặc định dùng const; chỉ dùng let khi thật sự cần gán lại.
  • let và const đều block-scope - sống trong cặp { } gần nhất.
  • const chặn GÁN LẠI biến, không “đóng băng” object (vẫn sửa được thuộc tính).

Vì sao tránh var?

var là cách cũ (trước 2015): phạm vi theo hàm chứ không theo block, lại bị hoisting (đẩy khai báo lên đầu) nên dễ sinh bug khó hiểu. Code mới gần như luôn dùng let/const; gặp var thường là code cũ.

JavaScript có 7 kiểu nguyên thuỷ (primitive): number, string, boolean, null, undefined, bigint, symbol - cộng với object (gồm cả mảng và hàm). Toán tử typeof cho biết kiểu của một giá trị:

typeof - và vài kết quả bất ngờ

typeof 42            // "number"
typeof "hi"          // "string"
typeof true          // "boolean"
typeof undefined     // "undefined"
typeof 10n           // "bigint"
typeof Symbol()      // "symbol"

typeof null          // "object"    <- bug lich su!
typeof {}            // "object"
typeof [1, 2]        // "object"    (mang la object - dung Array.isArray)
typeof function(){}  // "function"
  • 7 kiểu nguyên thuỷ: number, string, boolean, null, undefined, bigint, symbol.
  • Mọi thứ còn lại (mảng, hàm, ngày tháng…) đều là object.
  • typeof cho biết kiểu - nhưng có vài “quirk” cần nhớ (xem callout).

Hai quirk của typeof

typeof null === "object" là một bug lịch sử được giữ lại - null KHÔNG phải object. Và typeof [1,2] cũng ra "object" (mảng vốn là object); muốn chắc là mảng, dùng Array.isArray(x).

Khác C hay Python (có int và float riêng), JavaScript chỉ có một kiểu số dùng hằng ngày: number, chính là double IEEE 754 (64-bit). Số nguyên hay số thực đều dùng chung kiểu này (BigInt là kiểu riêng, chỉ dành cho số nguyên cực lớn) - tiện, nhưng kéo theo bẫy số thực gần đúng:

một kiểu number cho tất cả

typeof 7        // "number"
typeof 7.5      // "number"   (cung mot kieu!)

0.1 + 0.2       // 0.30000000000000004
0.1 + 0.2 === 0.3   // false

1 / 0           // Infinity
0 / 0           // NaN  (Not a Number)
Number.isInteger(7)   // true

9007199254740993n     // so nguyen RAT lon -> dung BigInt (hau to n)

Hệ quả nguy hiểm nhất là khi xử lý tiền. Cộng 0.10 nhiều lần bằng number - nó trông đúng nhưng không đúng:

Cộng 0.10 (10 xu) lặp lại:
Lưu bằng float / double
99.9999999999986
In ra (làm tròn 2 số): 100.00 - trông đúng!
✗ float == 100.00 ? → false
Lưu bằng số nguyên (xu)
10.000 xu
= 100.00 - đúng theo số xu đã cộng.
✓ 10000 == 1000 × 10
⚠️ Float trông đúng khi in ra (100.00), nhưng giá trị trong máy là 99.9999999999986 - KHÁC 100.00. Nên if tong == 100.00 sẽ SAI, và mỗi phép cộng/làm tròn lại trôi thêm. Với tiền, hãy lưu bằng số nguyên đơn vị nhỏ nhất (xu/đồng) hoặc kiểu thập phân chuẩn.
  • JS chỉ có một kiểu number = double IEEE 754; không tách int/float.
  • number là số GẦN ĐÚNG: đừng so hai number bằng === sau khi tính toán.
  • Có NaN (không phải số) và Infinity; số nguyên cực lớn dùng BigInt (10n).
  • TIỀN: lưu bằng số nguyên đơn vị nhỏ nhất (xu) - đừng dùng number/float.

Trung thực về tiền

Vì number là số thực gần đúng, lưu tiền bằng nó sẽ trôi số sau nhiều phép cộng và làm if tong === 100.00 thất bại. Hãy lưu bằng số nguyên xu (vd 10000 = 100,00đ) và chỉ chia khi hiển thị; với tính toán tài chính phức tạp, dùng thư viện thập phân chuẩn.

Chuỗi (string) đặt trong nháy đôi, nháy đơn, hoặc dấu huyền ` (template literal - chèn được biến). boolean chỉ có true/false. Còn hai “giá trị rỗng” hay nhầm lẫn: undefined (chưa gán) và null (cố ý rỗng).

chuỗi, template literal, và rỗng

const ten = "Lan";
const tuoi = 16;
const cau = `Meo con ${ten}, ${tuoi} tuoi`;   // template literal
console.log(cau);                               // Meo con Lan, 16 tuoi

let x;          // chua gan -> undefined
let y = null;   // co y de rong

Boolean("")     // false  (chuoi rong la falsy)
Boolean("0")    // true   (chuoi co ky tu -> truthy!)
Boolean([])     // true   (mang rong VAN truthy)
  • Template literal dùng dấu huyền và chèn biến, viết chuỗi nhiều dòng dễ dàng.
  • undefined = chưa gán (JS tự gán); null = cố ý để rỗng (bạn gán).
  • Mỗi giá trị có “tính đúng/sai” (truthy/falsy) khi đứng trong if.

Các giá trị falsy

Chỉ 7 giá trịfalsy: false, 0, "" (chuỗi rỗng), null, undefined, NaN (và 0n cho BigInt). Mọi thứ khác đều truthy - kể cả "0", "false", []{}.

Đây là chỗ JavaScript làm người mới đau đầu nhất. === so sánh cả kiểu lẫn giá trị, không ép kiểu - khác kiểu là false ngay. Còn == ép kiểu (coercion) hai bên về cùng kiểu RỒI mới so, sinh ra hàng loạt kết quả bất ngờ:

ép kiểu lặng lẽ

"5" - 2     // 3     (chuoi -> so)
"5" + 2     // "52"  (so -> chuoi; + uu tien NOI chuoi)

1 == "1"    // true   (ep kieu roi so)
1 === "1"   // false  (khac kieu -> false ngay)

0 == ""           // true
0 === ""          // false
null == undefined  // true
null === undefined // false
NaN === NaN        // false  (NaN khong bang ca chinh no!)
Biểu thức=====
1, "1"truefalse
0, ""truefalse
0, "0"truefalse
"", "0"falsefalse
null, undefinedtruefalse
NaN, NaNfalsefalse
  • LUÔN dùng === và !== - bỏ qua == để tránh bẫy ép kiểu.
  • Cần đổi kiểu thì làm TƯỜNG MINH: Number(x), String(x), Boolean(x).
  • NaN không bằng chính nó: kiểm tra bằng Number.isNaN(x).

Tiếp theo

Đã nắm biến, kiểu và cạm bẫy ép kiểu. Bài sau - “Rẽ nhánh & vòng lặp” - cho chương trình biết ra quyết địnhlặp lại công việc: if/else, switch, for, while - và truthy/falsy của bài này sẽ được dùng ngay.

Câu hỏi thường gặp

Mặc định dùng const; chỉ dùng let khi cần gán lại biến. TRÁNH var: nó phạm vi theo hàm (function scope) và bị “hoisting” nên dễ gây bug. Lưu ý: const chặn việc GÁN LẠI biến, chứ KHÔNG “đóng băng” object - bạn vẫn sửa được thuộc tính của object khai báo bằng const.

number của JavaScript là double IEEE 754 - số thực GẦN ĐÚNG. 0.1 và 0.2 không biểu diễn chính xác được trong hệ nhị phân, nên tổng ra 0.30000000000000004. Đừng so hai number bằng == ; và TUYỆT ĐỐI đừng lưu tiền bằng number (xem Bước 3).

Cùng bẫy float ở C: bài Biến & kiểu dữ liệu - khoá C cơ bản →

Đó là một bug lịch sử từ năm 1995, được giữ lại để không phá vỡ code cũ trên toàn web. Nhớ: typeof null === "object" nhưng null KHÔNG phải object. Mảng cũng cho ra "object" - muốn kiểm tra mảng hãy dùng Array.isArray(x).

undefined = “chưa có giá trị” (JS tự gán khi bạn khai báo mà chưa gán, hoặc hàm không return). null = “cố ý để rỗng” (do lập trình viên gán). typeof undefined"undefined", còn typeof null"object". null == undefinedtrue (do ép kiểu), nhưng null === undefinedfalse.

=== (so sánh nghiêm ngặt) KHÔNG ép kiểu: khác kiểu là false ngay. == ép kiểu hai bên về cùng kiểu RỒI mới so, sinh ra nhiều kết quả bất ngờ (0 == ""true…). Quy tắc nghề: LUÔN dùng ===!==. Chỉ cần biết == tồn tại để đọc code cũ.

Là việc JS tự đổi kiểu khi cần. Ví dụ "5" - 2 ra 3 (chuỗi → số), nhưng "5" + 2 ra "52" (số → chuỗi, vì + ưu tiên NỐI chuỗi). Hiểu để khỏi bất ngờ; còn khi thật sự cần đổi kiểu thì làm TƯỜNG MINH bằng Number(x), String(x), Boolean(x).

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Theo bài, mặc định nên khai báo biến bằng cái nào và vì sao tránh var?

  1. 1

    let vs const

    Khai báo const ten = "..." rồi thử gán lại ten = "...". Lỗi gì? Đổi sang let xem sao.

    Hoàn thành khi: const gán lại → TypeError: Assignment to constant variable. Đổi sang let thì gán lại được.

  2. 2

    typeof

    In typeof cho: 42, "hi", true, undefined, null, [1, 2], {}. Cái nào gây bất ngờ?

    Hoàn thành khi: null[1,2] đều ra "object" - bug lịch sử của null, và mảng vốn là object.

  3. 3

    Bẫy số thực

    In ra 0.1 + 0.20.1 + 0.2 === 0.3.

    Hoàn thành khi: 0.30000000000000004false - number là số gần đúng.

  4. 4

    == vs ===

    Đoán trước rồi kiểm: 0 == "", 0 === "", "1" == 1, "1" === 1, null == undefined, null === undefined.

    Hoàn thành khi: true, false, true, false, true, false. === khác kiểu là false ngay.

  5. 5

    Tiền

    Dùng công cụ ở Bước 3: cộng 0.10 nhiều lần. So float với số nguyên xu.

    Hoàn thành khi: Float trôi số (float == số đúng → false); lưu bằng số nguyên xu thì đúng tuyệt đối.

  6. 6

    Truthy / falsy

    Liệt kê các giá trị falsy của JS. "0"[] (mảng rỗng) là truthy hay falsy?

    Hoàn thành khi: Falsy: false, 0, "" , null, undefined, NaN (và 0n). "0"[] đều TRUTHY.