Lesson 0.2.1 — Values
0. Metadata (Thông tin bài học)
| Key | Value |
|---|---|
| Stage | 0 — JavaScript Language Foundation |
| Module | 0.2 — Values, Variables & Types |
| Lesson | 0.2.1 — Values |
| Competency | C01 — JavaScript Language |
| Depth Target | L2–L3 (Explain → Use) |
| Prerequisites | Lesson 0.1.3 — JavaScript Execution ở mức khái niệm |
| Estimated Cognitive Load | Low–Medium |
1. Why This Exists (Vì sao cần học)
Bạn chạy đoạn code sau:
console.log([] === []);Kết quả là false. Nhưng hai bên đều là array rỗng — tại sao không bằng nhau?
Hoặc đoạn này:
const a = "hello";
const b = a;
// b thay đổi? Không — string là immutable.Nhưng:
const x = { count: 1 };
const y = x;
y.count = 2;
console.log(x.count); // 2Junior thường nhìn code và thấy "biến a bằng 5", "biến x là object". Nhưng đằng sau đó, JavaScript không làm việc với "biến" — nó làm việc với value. Biến chỉ là cái tên gắn vào value.
Nếu không phân biệt được value là gì, primitive khác object như thế nào, và identity có nghĩa là gì, bạn sẽ:
- So sánh object bằng
===và ngạc nhiên kết quả sai. - Nghĩ
constngăn object thay đổi. - Không hiểu tại sao
typeof nulllà"object".
Lesson này xây mental model về value trước khi bạn học variable, type, và equality.
2. Prerequisites (Yêu cầu đầu vào)
Trước khi học bài này, bạn cần biết:
- JavaScript engine parse rồi mới execute code.
typeoflà toán tử cấp language.- Có sự khác biệt giữa Browser và Node.js runtime.
3. Learning Objectives (Mục tiêu học tập)
Sau bài này, bạn có thể:
- Phân biệt value và variable ở mức khái niệm.
- Phân loại một value thành Primitive hoặc Object.
- Giải thích tại sao
[] === []làfalsebằng khái niệm identity. - Dự đoán kết quả của
typeofvà===cho các value phổ biến. - Nhận diện immutable primitive và mutable object.
4. Mental Model (Mô hình tư duy)
Value vs Variable (Giá trị vs Biến)
Value là "thứ" thực sự tồn tại trong memory khi JavaScript chạy. Variable là tên (binding) gắn vào value đó.
const score = 100;100là value.scorelà variable trỏ đến value100.
Two Kinds of Values (Hai loại giá trị)
Primitive: Đơn giản, không thể thay đổi nội bộ (immutable), không có "danh tính" riêng. Số 5 ở đâu cũng là số 5.
Object: Cấu trúc phức tạp, có thể thay đổi nội bộ (mutable), có "danh tính" riêng. Mỗi lần bạn viết {}, JavaScript tạo ra một object hoàn toàn mới trong memory — dù nội dung nhìn giống hệt nhau.
Identity (Danh tính)
Identity là cách engine phân biệt hai object trong memory.
{} === {} // falseTại sao? Vì bên trái tạo ra object A, bên phải tạo ra object B. === kiểm tra identity: "Đây có phải cùng một object trong memory không?" → Không.
5. Core Concepts (Các khái niệm cốt lõi)
Essential (Bắt buộc)
5.1 What Is a Value? (Value là gì?)
Value là đơn vị dữ liệu cơ bản mà JavaScript engine thao tác. Mọi expression trong JavaScript đều evaluate về một value.
42; // value: number 42
"hello"; // value: string "hello"
{}; // value: object
[]; // value: array (một loại object)5.2 Primitive Values (Giá trị nguyên thủy)
Các primitive value trong JavaScript:
| Type | Ví dụ | Đặc điểm |
|---|---|---|
string | "hello" | Immutable |
number | 42, 3.14 | Immutable |
boolean | true, false | Immutable |
null | null | Immutable |
undefined | undefined | Immutable |
bigint | 9007199254740991n | Immutable |
symbol | Symbol("id") | Immutable |
Immutable có nghĩa là value không thể thay đổi từ bên trong. Bạn không thể sửa ký tự thứ 3 của string:
const name = "Ada";
name[0] = "B"; // Không có lỗi, nhưng không có tác dụng
console.log(name); // "Ada"Awareness — Ngoại lệ
Symbol:
Symbollà primitive, nhưng mỗiSymbol("id")tạo ra value duy nhất trong suốt vòng đời program. Vì vậySymbol("a") !== Symbol("a"). Đây là exception cho mental model "compared by value" — sẽ đào sâu ở Lesson 0.2.3.
5.3 Object Values (Giá trị object)
Object value bao gồm:
| Category | Ví dụ | Đặc điểm |
|---|---|---|
| Plain Object | { name: "A" } | Mutable, có identity |
| Array | [1, 2, 3] | Mutable, có identity |
| Function | () => {} | Mutable, có identity, callable |
| Date | new Date() | Mutable, có identity |
| RegExp | /abc/ | Mutable, có identity |
| Map / Set | new Map() | Mutable, có identity |
Mutable có nghĩa là nội dung bên trong có thể thay đổi mà value đó vẫn là "chính nó":
const user = { name: "A" };
user.name = "B"; // Object vẫn là object cũ, nhưng nội dung đổi5.4 Equality & Identity (Bằng nhau và Danh tính)
Với primitive, === so sánh value:
5 === 5; // true
"hi" === "hi"; // trueVới object, === so sánh identity (không phải nội dung):
{ a: 1 } === { a: 1 }; // false
[1] === [1]; // falsePractical Tip (Quyết định thực tế)
Khi so sánh hai array hoặc object bằng ===, bạn đang hỏi: "Chúng có phải là cùng một thực thể trong memory không?" — không phải "Nội dung của chúng có giống nhau không?"
Supporting (Hỗ trợ)
- Wrapper Objects:
String,Number,Booleanlà object constructors. Khi bạn gọi"hello".toUpperCase(), engine tạm thời wrap primitive string thành object để truy cập method, rồi unwrap lại. Bạn không cần tự tạonew String(). - Function là object: Mọi function đều là object value, nhưng
typeoftrả về"function"vì tiện lợi.
Awareness (Biết tồn tại)
BigIntvàSymbollà primitive types đặc biệt. Sẽ đào sâu ở Lesson 0.2.3.typeof null === "object"là lỗi lịch sử của JavaScript, không thể sửa vì break legacy code.
Out of Scope (Không học trong bài này)
- Reference mechanics chi tiết (sẽ học ở Lesson 0.2.2).
==vs===vsObject.is(sẽ học ở Lesson 0.3.2).- Prototype chain.
- Deep clone / shallow copy (sẽ học ở Lesson 0.6.8).
- Memory allocation internals.
6. Worked Example (Ví dụ phân tích từng bước)
Đoạn code:
const a = 100;
const b = 100;
console.log(a === b);
const x = { id: 1 };
const y = { id: 1 };
console.log(x === y);Phân tích từng bước:
Step 1 — Primitive comparison:
100là primitive value.agắn vào value100.bgắn vào value100.a === bso sánh value:100 === 100→true.
Step 2 — Object creation:
{ id: 1 }đầu tiên tạo ra một object value mới trong memory.xgắn vào object này.{ id: 1 }thứ hai tạo ra một object value khác trong memory.ygắn vào object khác này.
Step 3 — Object comparison:
x === yso sánh identity: "Có phải cùng một object trong memory không?"- Không — đây là hai object riêng biệt →
false.
Kết luận: Sự khác biệt nằm ở loại value. Primitive so sánh bằng nội dung. Object so sánh bằng identity.
7. Prediction Exercise (Bài tập dự đoán)
Đừng chạy code. Dự đoán output và giải thích tại sao.
Câu 1:
console.log(typeof "hello");
console.log(typeof 42);
console.log(typeof true);[Đáp án & Giải thích]
"string"
"number"
"boolean"Cả ba đều là primitive values. typeof trả về tên type tương ứng.
Câu 2:
console.log(typeof {});
console.log(typeof []);
console.log(typeof function() {});[Đáp án & Giải thích]
"object"
"object"
"function"{} và [] đều là object values. typeof [] là "object" (array không có type riêng trong typeof). typeof function là "function" — đây là ngoại lệ lịch sử tiện lợi, dù function vẫn là object.
Câu 3:
console.log({} === {});
console.log([] === []);[Đáp án & Giải thích]
false
falseMỗi object literal tạo ra một object value mới với identity riêng. === so sánh identity, không phải nội dung.
Câu 4:
const a = null;
console.log(typeof a);[Đáp án & Giải thích]
"object"null là primitive value, nhưng typeof null trả về "object" vì lỗi đầu tiên của JavaScript specification (không thể sửa vì backward compatibility). Đây là edge case bắt buộc phải nhớ.
8. Implementation Lab (Bài lab thực hành)
Nhiệm vụ: Phân loại các value sau vào bảng.
42
"hello"
true
null
undefined
{}
[]
() => {}
new Date()| Value | Primitive / Object | typeof | Immutable? |
|---|---|---|---|
42 | |||
"hello" | |||
true | |||
null | |||
undefined | |||
{} | |||
[] | |||
() => {} | |||
new Date() |
[Đáp án & Giải thích]
| Value | Primitive / Object | typeof | Immutable? |
|---|---|---|---|
42 | Primitive | "number" | Yes |
"hello" | Primitive | "string" | Yes |
true | Primitive | "boolean" | Yes |
null | Primitive | "object" | Yes |
undefined | Primitive | "undefined" | Yes |
{} | Object | "object" | No |
[] | Object | "object" | No |
() => {} | Object | "function" | No |
new Date() | Object | "object" | No |
Lưu ý: typeof null === "object" là ngoại lệ duy nhất trong bảng — primitive nhưng typeof báo object.
9. Edge Cases (Các trường hợp ngoại lệ)
typeof null === "object"
typeof null; // "object"null là primitive value đại diện cho "không có object". Nhưng vì lý do lịch sử trong ECMAScript, typeof null trả về "object".
Hậu quả: Kiểm tra if (typeof x === "object") sẽ match cả null. Trong production, cần loại trừ:
if (x !== null && typeof x === "object") {
// x thực sự là object
}typeof [] === "object"
typeof []; // "object"Array là object value. typeof không phân biệt array và plain object. Để kiểm tra array, dùng:
Array.isArray([]); // trueFunction là object nhưng typeof đặc biệt
typeof function() {}; // "function"Function là object value (có identity, có thể thêm property), nhưng typeof có riêng chuỗi "function" để tiện kiểm tra.
10. Debug Lab (Bài lab gỡ lỗi)
Tình huống: Bạn viết hàm kiểm tra cấu hình:
function isSameConfig(a, b) {
return a === b;
}
const configA = { theme: "dark" };
const configB = { theme: "dark" };
console.log(isSameConfig(configA, configB));Symptom (Triệu chứng): Luôn trả về false dù hai object có nội dung giống hệt nhau.
Reproduction (Tái hiện lỗi): Chạy code trên.
Evidence (Bằng chứng): Output là false. Không có lỗi thrown.
Hypothesis (Giả thuyết): === giữa hai object so sánh identity, không phải nội dung. configA và configB là hai object value riêng biệt trong memory.
Verification (Xác minh):
console.log(configA === configA); // true — cùng identity
console.log(configA === configB); // false — khác identityRoot Cause (Nguyên nhân gốc rễ): Nhầm lẫn mental model equality. Người viết mong đợi === so sánh "nội dung giống nhau" như primitive, nhưng object comparison dựa trên identity.
Fix (Sửa): Nếu cần so sánh nội dung object, phải so sánh từng property hoặc dùng utility (JSON.stringify cho simple case, hoặc deep equality library). Ở Stage 0, cách đơn giản nhất:
function isSameConfig(a, b) {
return a.theme === b.theme;
}Prevention (Phòng ngừa):
- Khi so sánh object, luôn tự hỏi: "Tôi muốn so sánh identity hay nội dung?"
- Nếu so sánh nội dung, đừng dùng
===trực tiếp trên object.
11. Production Scenario (Tình huống thực tế)
Context (Bối cảnh): Trong React component, bạn memoize một prop object:
const config = { apiKey: "secret" };
function App() {
return <Child config={config} />;
}Sau đó bạn refactor:
function App() {
return <Child config={{ apiKey: "secret" }} />;
}Symptom: Component Child re-render liên tục dù prop nhìn giống hệt.
Root Cause: Mỗi lần App render, { apiKey: "secret" } tạo ra một object value mới với identity mới. React so sánh identity của props (shallow comparison) và thấy khác → re-render.
Lesson: Object identity ảnh hưởng trực tiếp đến rendering behavior trong production. Sẽ đào sâu ở Stage 8.
12. AI-Assisted Exercise (Bài tập với AI)
Level A — Ask (Hỏi)
- Tự trả lời: "Tại sao
typeof nulllà"object"?" Viết câu trả lời của bạn. - Hỏi AI cùng câu hỏi đó.
- So sánh: AI có nhắc đến "lỗi lịch sử của ECMAScript implementation" và "backward compatibility" không?
- Verify: Tra MDN hoặc ECMAScript specification để xác nhận.
Gợi ý
Nhiều AI sẽ đoán mò hoặc giải thích sai về typeof null. Đây là bài kiểm tra kỹ năng verify thông tin kỹ thuật.
Đáp án tham khảo
- Bạn nghĩ
typeof null là "object" vì đây là một lỗi lịch sử trong implementation đầu tiên của JavaScript. Hồi đó, engine đánh dấu type bằng các bit flag ở đầu vùng nhớ. Object có tag bắt đầu bằng 000, và null cũng được biểu diễn bằng toàn bit 0 (0x00). Khi kiểm tra type, engine nhìn vào các bit đầu, thấy 000 thì tưởng là object. Lỗi này không thể sửa vì sửa sẽ break hàng triệu dòng code đang chạy — đó là backward compatibility. Nên đến giờ typeof null vẫn là "object", dù null hoàn toàn không phải object.
- AI trả lời
AI thường nói:
"
typeof nulltrả về"object"vìnullđược coi là một kiểu object đặc biệt trong JavaScript. Đây là một đặc điểm của ngôn ngữ. Một số người cho rằng đây là bug, nhưng thực tế nó đã tồn tại từ lâu và không thể thay đổi vì lý do tương thích ngược."
Hoặc AI có thể nói:
"
nullđại diện cho một object rỗng, nêntypeof nulllà"object"."
- So sánh
Câu trả lời của AI có thể đúng ở chỗ nhắc đến "backward compatibility" hoặc "lỗi lịch sử", nhưng thường thiếu chi tiết kỹ thuật cụ thể. AI hiếm khi giải thích tại sao lỗi này xảy ra ở mức implementation — vì null được biểu diễn bằng 0x00 (tất cả bit 0), trùng với bit pattern của object pointer trong engine đời đầu.
Nếu AI nói "null đại diện cho object rỗng" — đây là hiểu nhầm nghiêm trọng. null không phải object, không có prototype, không có property. Nó là một primitive value đại diện cho "không có giá trị".
- Điểm AI nói sai hoặc quá mơ hồ
AI thường dùng từ "được coi là một kiểu object đặc biệt" hoặc "đại diện cho object rỗng". Điều này gợi ý rằng null có ý nghĩa semantic là object — hoàn toàn sai. null là primitive, không phải object.
Ngoài ra, AI thường không nhắc đến bit pattern hoặc type tag trong engine implementation — đây là nguyên nhân gốc rễ. Câu trả lời của AI mang tính "bề mặt" và đôi khi gây hiểu nhầm về bản chất của null.
- Kết luận
Nếu AI không phân biệt rõ: null là primitive, không phải object; và lỗi typeof null xuất phát từ bit representation trong engine đời đầu chứ không phải từ ý định thiết kế — bạn đã verify được thông tin chính xác hơn AI. Đây là lý do ta luôn kiểm chứng bằng spec thay vì tin hoàn toàn vào AI.
13. Teach Back (Dạy lại)
Yêu cầu: Giải thích trong 2 phút (viết hoặc nói):
"Primitive value khác Object value như thế nào? Và tại sao
[] === []lại làfalse?"
Yêu cầu:
- Có nhắc đến immutable vs mutable không?
- Có nhắc đến identity không?
- Có giải thích
===behavior khác nhau giữa hai loại không? - Người nghe có thể dự đoán
{} === {}không?
Mô phỏng
- Bạn nói
Primitive là giá trị đơn giản: string, number, boolean, null, undefined, symbol, bigint. Đặc điểm là immutable — tạo ra rồi thì không sửa được, chỉ có thể thay thế bằng giá trị mới.
Object là container: object, array, function. Đặc điểm là mutable — tạo ra rồi vẫn có thể thêm, xóa, sửa bên trong.
Khi so sánh bằng ===, primitive so sánh theo giá trị. 5 === 5 là true vì cả hai bên đều là số 5. "a" === "a" là true vì cùng chuỗi "a".
Object thì khác. === không so sánh nội dung bên trong, mà so sánh identity — tức là "có phải là cùng một object trong bộ nhớ không".
Khi viết [] === [], bên trái tạo ra một array mới ở một vùng nhớ. Bên phải tạo ra một array mới ở vùng nhớ khác. Hai vùng nhớ khác nhau, hai identity khác nhau. Nên false.
Còn nếu viết:
const a = [];
const b = a;
a === b; // trueVì b không tạo array mới, nó chỉ trỏ đến cùng array với a. Cùng identity nên true.
Nói chung: Primitive so sánh giá trị, Object so sánh identity. Vì vậy {} === {} cũng là false — hai object riêng biệt.
💡 Dễ nhớ: Primitive giống như tiền mặt — hai tờ 100k thì bằng nhau vì cùng giá trị. Object giống như chìa khóa nhà — hai chìa khóa nhìn giống hệt nhau nhưng mở hai căn nhà khác nhau.
===không hỏi "có giống nhau không", mà hỏi "có phải là cùng một cái không".
Gợi ý đánh giá bản thân
- Đồng nghiệp có tự dự đoán được
{} === {}làfalsekhông? - Họ có hiểu tại sao
const a = []; a.push(1)được nhưngconst s = "a"; s.toUpperCase()lại không sửa đượcskhông? - Nếu họ hỏi "vậy
===so sánh reference à?" — bạn sửa lại bằng từ identity được không?
⚠️ Lưu ý: Reference ≠ Identity
Reference và Identity — đừng nhầm là một.
Hai khái niệm này liên quan rất chặt, nhưng không phải là một.
const a = { x: 1 };
Variable / Binding: a
│
│ reference
▼
┌───────────────┐
│ Object │
│ Identity #1 |
│ │
│ { x: 1 } │
└───────────────┘- Identity là danh tính của chính object — trả lời câu hỏi:
“Đây có phải là cùng một object không?” Identity #1 chính là object { x: 1 }.
- Reference là mối liên hệ từ một binding đến object — trả lời câu hỏi:
“Binding này đang tham chiếu đến object nào?”
Ví dụ:
const a = { x: 1 };
const b = a;Có thể hình dung:
a ── reference ──┐
├──→ Identity #1
b ── reference ──┘ { x: 1 }a và b là hai binding khác nhau, nhưng cùng reference đến một identity.
a === b; // trueNgược lại:
const a = { x: 1 };
const b = { x: 1 };thì:
a ──reference──→ Identity #1
{ x: 1 }
b ──reference──→ Identity #2
{ x: 1 }Nội dung giống nhau, nhưng là hai object khác nhau, nên có hai identity khác nhau.
a === b; // false💡 Cách nhớ
Reference = "đang trỏ tới đâu?"
Identity = "đó là object nào?"
Vì vậy, khi nói về === với Object, nên nói:
===kiểm tra object identity: hai bên có phải đang tham chiếu đến cùng một object hay không.
Đừng đồng nhất reference = identity. Một identity có thể được nhiều binding cùng reference tới:
a ──┐
├── reference ──→ Identity #1
b ──┘Đó chính là lý do:
const a = [];
const b = a;
a === b; // true14. Assessment (Đánh giá)
| Objective (Mục tiêu) | Format (Hình thức đánh giá) | Depth |
|---|---|---|
| Phân biệt Primitive và Object | Classification (Phân loại) | L2 |
| Giải thích identity | Explain (Giải thích) | L2 |
Dự đoán typeof và === | Prediction (Dự đoán) | L2 |
| Debug object comparison bug | Debug (Gỡ lỗi) | L3 |
15. Exit Criteria (Tiêu chí qua bài)
- [ ] Có thể phân loại một value bất kỳ thành Primitive hoặc Object.
- [ ] Có thể giải thích tại sao
[] === []làfalsebằng khái niệm identity. - [ ] Có thể dự đoán đúng
typeofcho 8/10 value phổ biến (bao gồm cảnullvà[]). - [ ] Có thể giải thích tại sao primitive là immutable và object là mutable.
- [ ] Có thể debug tình huống so sánh object bằng
===và nhận ra đó là identity comparison.
16. Spiral Connection (Liên kết xoắn ốc)
Previous (Trước): Execution Flow — Bạn đã biết engine parse rồi execute code. Giờ bạn hiểu engine thao tác với value trong quá trình đó.
Current (Hiện tại): Value Mental Model — Bạn biết JavaScript có hai loại value: Primitive (immutable, no identity) và Object (mutable, has identity). Bạn biết
typeofvà===behavior khác nhau tùy loại.
Next (Tiếp theo):
- Lesson 0.2.2 — Variables & Bindings: Bạn sẽ học variable không phải là "hộp chứa value" mà là "nhãn dán gắn vào value". Từ đó hiểu
constvsletvsvarvà tại saoconst objectvẫn cho phép mutation.- Lesson 0.2.3 — Primitive Types: Đào sâu từng primitive type: Number, String, Boolean, Null, Undefined, BigInt, Symbol.
- Lesson 0.2.4 — Object Values: Object, Array, Function, Date, RegExp, Map, Set — chi tiết hơn về object category.
- Lesson 0.6.8 — Spread & Shallow Copy: Identity và reference sẽ quay lại khi bạn học copy object.
- Stage 2 — Object Model: Prototype, internal slots, object mechanics đầy đủ.