Lesson 0.6.7 — Destructuring
0. Metadata
| Field | Value |
|---|---|
| Stage | 0 — JavaScript Language Foundation |
| Module | 0.6 — Data Structures |
| Lesson | 0.6.7 |
| Competency | C01.6 — Arrays / Objects |
| Depth Target | L2–L3 |
| Prerequisites | Objects (0.6.5), Object Utilities (0.6.6), Arrays (0.6.2), Array Iteration (0.6.3) |
| Estimated Cognitive Load | Medium |
1. Why This Exists (Vì sao cần học)
Bạn đã biết truy cập object bằng obj.name và obj["name"]. Nhưng khi cần lấy nhiều property cùng lúc, code trở nên lặp lại và nói về cơ chế thay vì intent.
Xét đoạn code:
function displayUser(user) {
const name = user.name;
const email = user.email;
const role = user.role || "guest";
const theme = user.settings ? user.settings.theme : "light";
return `${name} (${email}) — ${role}, theme: ${theme}`;
}Vấn đề cốt lõi
const name = user.name nói: "Tôi đang lấy property name từ user." Nhưng intent thực sự chỉ là: "Tôi cần name, email, role từ user." Destructuring cho phép bạn viết intent đó trực tiếp.
Ngoài ra, destructuring còn cung cấp:
- Default value:
role = "guest"khi property missing hoặcundefined. - Rename:
name: displayNameđể tránh xung đột tên biến. - Nested access:
settings.themetrong một bước. - Array unpacking: lấy phần tử theo vị trí thay vì index.
Bài này dạy bạn dùng destructuring như một khai báo intent: tôi cần những gì từ structure này.
2. Prerequisites (Yêu cầu đầu vào)
Trước khi học bài này, bạn cần:
- Truy cập object bằng dot và bracket notation (0.6.5).
- Biết
Object.entriestrả về[key, value]pairs (0.6.6). - Biết array index và
length(0.6.2). - Hiểu
const/letvà assignment (0.2.2).
WARNING
Nếu bạn chưa chắc tại sao obj.missing trả về undefined nhưng const { a } = null lại throw, quay lại 0.6.5. Sự khác biệt giữa "property không tồn tại" và "object không tồn tại" là trung tâm của edge cases trong bài này.
3. Learning Objectives (Mục tiêu học tập)
Sau bài này, bạn có thể:
- Sử dụng object destructuring để trích xuất nhiều property trong một câu lệnh.
- Sử dụng array destructuring để trích xuất phần tử theo vị trí.
- Áp dụng default values khi property là
undefined. - Đổi tên property trong destructuring để tránh xung đột.
- Truy cập nested property qua nested destructuring.
- Sử dụng rest pattern (
...rest) trong destructuring để lấy phần còn lại. - Nhận diện khi destructuring sẽ throw (source là
null/undefined).
4. Mental Model (Mô hình tư duy)
Mental Model
Destructuring = Mở hộp và lấy đồ theo tên/vị trí
Object Destructuring (Mở hộp có nhãn)
{ name, email } = user
↓
Từ hộp `user`, lấy món đồ tên `name` → biến `name`
Từ hộp `user`, lấy món đồ tên `email` → biến `email`
{ name: displayName } = user
↓
Lấy món `name`, đặt vào biến `displayName`
{ role = "guest" } = user
↓
Lấy món `role`. Nếu hộp không có hoặc là undefined → dùng "guest"
Array Destructuring (Mở hộp theo thứ tự)
[first, second] = items
↓
Lấy phần tử 0 → biến `first`
Lấy phần tử 1 → biến `second`
[first, , third] = items
↓
Lấy 0, bỏ qua 1, lấy 2
[head, ...tail] = items
↓
Lấy 0, phần còn lại thành mảng `tail`Quy tắc vàng:
- Destructuring là pattern matching trên shape của value.
- Object destructuring dựa trên tên key, không quan tâm thứ tự.
- Array destructuring dựa trên vị trí index.
- Default value chỉ kích hoạt khi property là
undefined, không phảinull,0,"",false. - Rest (
...) phải ở cuối pattern.
5. Core Concepts (Các khái niệm cốt lõi)
Essential (Bắt buộc)
| Concept | Ý nghĩa |
|---|---|
| Object Destructuring | const { a, b } = obj — tạo biến a và b từ property cùng tên. |
| Array Destructuring | const [x, y] = arr — tạo biến x (index 0), y (index 1). |
| Default Value | const { a = 1 } = obj — nếu obj.a là undefined, a = 1. |
| Rename | const { a: b } = obj — lấy property a, đặt vào biến b. |
| Nested Destructuring | const { a: { b } } = obj — truy cập obj.a.b trong một pattern. |
| Rest in Destructuring | const { a, ...rest } = obj hoặc const [x, ...rest] = arr. rest chứa phần còn lại. |
Supporting (Hỗ trợ)
| Concept | Ý nghĩa |
|---|---|
| Destructuring in Parameters | function fn({ name }) — destructuring ngay trong parameter list. |
| Swap Variables | [a, b] = [b, a] — hoán đổi không cần biến tạm. |
Awareness (Biết tồn tại)
| Concept | Lý do chưa đào sâu |
|---|---|
| Computed key destructuring | const { [expr]: name } = obj. Dùng bracket trong pattern. Học khi cần dynamic key. |
| Iterator destructuring | const [a, b] = new Set([1, 2]). Dựa trên iterator protocol. Thuộc Stage 2. |
Out of Scope (Không thuộc bài này)
- Destructuring với complex nested beyond 2 levels (cognitive load).
for...ofdestructuring (Stage 2 — Iteration protocol).- TypeScript tuple destructuring (Stage 6).
- React props destructuring pattern (Stage 8 — preview có thể nhưng không đào sâu).
6. Worked Example (Ví dụ phân tích từng bước)
Bài toán: Viết function nhận API response và trích xuất thông tin hiển thị.
const response = {
status: 200,
data: {
user: {
id: 42,
name: "Alice",
email: "alice@example.com",
profile: {
role: "admin",
theme: "dark"
}
}
}
};Yêu cầu:
- Lấy
name,email. - Lấy
roletừ nestedprofile, đổi tên thànhuserRole. - Nếu
thememissing, default là"light". - Lấy tất cả property còn lại của
profilevàootherProfile.
function extractInfo(response) {
const user = response.data.user;
const name = user.name;
const email = user.email;
const userRole = user.profile.role;
const theme = user.profile.theme ? user.profile.theme : "light";
return { name, email, userRole, theme };
}function extractInfo({ data: { user } }) {
const {
name,
email,
profile: {
role: userRole,
theme = "light",
...otherProfile
}
} = user;
return { name, email, userRole, theme, otherProfile };
}Walkthrough
Step 1 — Parameter Destructuring{ data: { user } } unpack ngay trong parameter. response → data → user. Không cần const user = response.data.user.
Step 2 — Object Destructuring name, emailconst { name, email } = user tạo biến name và email từ property cùng tên. Nếu property missing → undefined.
Step 3 — Nested Destructuring + Renameprofile: { role: userRole } đi vào user.profile, lấy role, đặt vào biến userRole. Rename giúp tránh xung đột với từ khóa hoặc tên rõ hơn.
Step 4 — Default Valuetheme = "light" — nếu user.profile.theme là undefined, biến theme nhận "light". Nếu là null, theme vẫn là null (default không kích hoạt).
Step 5 — Rest...otherProfile lấy tất cả property còn lại của profile (ngoài role và theme) thành object mới.
Key Insight: Destructuring không chỉ ngắn gọn hơn — nó khai báo shape của data mà function cần. Đọc parameter là biết function mong đợi gì từ input.
7. Prediction Exercise (Bài tập dự đoán)
Đừng chạy code. Đọc và dự đoán output, sau đó giải thích tại sao.
Câu 1
const user = { name: "Alice", age: 24 };
const { name: fullName, role = "user" } = user;
console.log(fullName, role);Câu 2
const coords = [10, 20, 30, 40];
const [x, , ...rest] = coords;
console.log(x, rest);Câu 3
const user = { profile: { name: "Bob" } };
const { profile: { name, age = 18 } } = user;
console.log(name, age);Câu 4
const data = null;
const { value } = data;
console.log(value);Câu 5
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b);[Đáp án & Giải thích]
Câu 1: "Alice" "user" — Rename + Default
- Giải thích:
name: fullNamelấy propertyname, đặt vào biếnfullName.rolekhông tồn tại tronguser→undefined→ default"user"kích hoạt.
Câu 2: 10 [30, 40] — Skip + Rest
- Giải thích:
[x, , ...rest]lấy index 0 (10), bỏ qua index 1 (20), rest lấy từ index 2 đến hết ([30, 40]).
Câu 3: "Bob" 18 — Nested + Default
- Giải thích: Đi vào
user.profile, lấyname="Bob".agekhông tồn tại trongprofile→undefined→ default18.
Câu 4: TypeError: Cannot destructure property 'value' of 'null' — Source là null
- Giải thích: Destructuring yêu cầu source phải là object (hoặc array).
nullkhông phải object → throw. Khác vớidata.value(trả vềundefined).
Câu 5: 2 1 — Swap
- Giải thích:
[a, b] = [b, a]unpack mảng[2, 1]vàoavàb. Hoán đổi không cần biến tạm.
8. Implementation Lab (Bài lab thực hành)
Level 1 — Guided (Có hướng dẫn)
Viết function formatUser dùng destructuring trong parameter để lấy name, email, và role với default "guest".
function formatUser(___________) {
return `${name} <${email}> (${role})`;
}
const user = { name: "Alice", email: "a@b.com" };
console.log(formatUser(user));
// "Alice <a@b.com> (guest)"Gợi ý
Destructuring object ngay trong parameter: function formatUser({ name, email, role = "guest" }).
[Đáp án tham khảo]
function formatUser({ name, email, role = "guest" }) {
return `${name} <${email}> (${role})`;
}
const user = { name: "Alice", email: "a@b.com" };
console.log(formatUser(user));
// "Alice <a@b.com> (guest)"
console.log(formatUser({ name: "Bob", email: "b@c.com", role: "admin" }));
// "Bob <b@c.com> (admin)"Giải thích:
- Destructuring trong parameter khai báo ngay: function cần object có
name,email, và tùy chọnrole. role = "guest"cung cấp default khi missing hoặcundefined.- Không cần
const name = user.nametrong body.
Level 2 — Partial Scaffold (Khung sẵn)
Hoàn thành destructuring để trích xuất thông tin từ nested API response.
function extractUser(response) {
const {
_______: _______,
data: {
user: {
_______,
profile: {
_______: avatar,
_______ = "light"
}
}
}
} = response;
return { status, name, avatar, theme };
}
const api = {
status: 200,
data: {
user: {
name: "Alice",
profile: { avatar: "a.jpg", theme: "dark" }
}
}
};
console.log(extractUser(api));
// { status: 200, name: "Alice", avatar: "a.jpg", theme: "dark" }[Đáp án tham khảo]
function extractUser(response) {
const {
status,
data: {
user: {
name,
profile: {
avatar,
theme = "light"
}
}
}
} = response;
return { status, name, avatar, theme };
}
const api = {
status: 200,
data: {
user: {
name: "Alice",
profile: { avatar: "a.jpg", theme: "dark" }
}
}
};
console.log(extractUser(api));
// { status: 200, name: "Alice", avatar: "a.jpg", theme: "dark" }Giải thích:
statuslấy trực tiếp từresponse.data: { user: { name, profile: ... } }đi sâu nested.avatarlà shorthand destructuring khi tên biến trùng tên property. Nếu cần đổi tên (ví dụavatar: userAvatar) mới dùng dạng dài.theme = "light"có default.
Level 3 — Independent (Tự viết)
Viết các function sau sử dụng destructuring:
// 1. getFirstAndLast(items) → Trả về { first, last } dùng array destructuring
// Ví dụ: getFirstAndLast(["a", "b", "c"]) → { first: "a", last: "c" }
// 2. extractConfig(settings) → Lấy host, port (default 3000), rename timeout → maxTimeout
// Ví dụ: extractConfig({ host: "localhost", timeout: 5000 })
// → { host: "localhost", port: 3000, maxTimeout: 5000 }
// 3. parseCoords(point) → point là { coords: [x, y] }. Dùng nested destructuring
// Ví dụ: parseCoords({ coords: [10, 20] }) → { x: 10, y: 20 }
// Sử dụng:
console.log(getFirstAndLast(["red", "green", "blue"]));
// { first: "red", last: "blue" }
console.log(extractConfig({ host: "api.example.com" }));
// { host: "api.example.com", port: 3000, maxTimeout: undefined }
console.log(parseCoords({ coords: [5, 10] }));
// { x: 5, y: 10 }[Đáp án tham khảo]
// middleAndLast sẽ là rest
function getFirstAndLast(items) {
const [first, ...middleAndLast] = items;
const last = middleAndLast[middleAndLast.length - 1] || first;
return { first, last };
}Hoặc đơn giản hơn:
function getFirstAndLast(items) {
const [first] = items;
const [last] = items.slice(-1);
return { first, last };
}function extractConfig(settings) {
const { host, port = 3000, timeout: maxTimeout } = settings;
return { host, port, maxTimeout };
}
function parseCoords(point) {
const { coords: [x, y] } = point;
return { x, y };
}
console.log(getFirstAndLast(["red", "green", "blue"]));
// { first: "red", last: "blue" }
console.log(extractConfig({ host: "api.example.com" }));
// { host: "api.example.com", port: 3000, maxTimeout: undefined }
console.log(parseCoords({ coords: [5, 10] }));
// { x: 5, y: 10 }Giải thích:
getFirstAndLast:[first, ...rest]lấy phần tử đầu và phần còn lại.rest[rest.length - 1]lấy cuối. Nếu mảng 1 phần tử,restrỗng, dùng|| first.const [first] = itemslấy phần tử đầu bằng array destructuring.items.slice(-1)trả về mảng chứa phần tử cuối.const [last]destructuring mảng đó để lấy giá trị.- Cả hai đều dùng array destructuring, không mutate
items. extractConfig:port = 3000default.timeout: maxTimeoutrename.parseCoords:{ coords: [x, y] }nested array destructuring trong object.
9. Edge Cases (Các trường hợp ngoại lệ)
Destructuring null hoặc undefined throw
const data = null;
const { name } = data; // TypeErrorTại sao: Destructuring cần source là object (hoặc array). null/undefined không thể convert.
Cách nhận biết: TypeError khi API trả về null thay vì object.
Cách xử lý: Guard clause hoặc default object:
const { name } = data || {};Default value chỉ kích hoạt với undefined
const { role = "guest" } = { role: null };
console.log(role); // nullTại sao: Default chỉ áp dụng khi property là undefined. null là giá trị explicit, không trigger default.
Cách nhận biết: Biến nhận null thay vì default value.
Cách xử lý: Nếu cần xử lý cả null, dùng nullish coalescing sau destructuring (Stage 0.4.3/Stage 1), hoặc validate trước.
Missing intermediate nested property throw
const user = {};
const { profile: { name } } = user;
// TypeError: Cannot destructure property 'name' of 'undefined'Tại sao: user.profile là undefined. Đi sâu vào undefined.name throw.
Cách nhận biết: TypeError khi destructuring nested object mà level trung gian missing.
Cách xử lý: Cung cấp default cho intermediate:
const { profile: { name } = {} } = user;Hoặc guard clause.
Rest phải ở cuối
const [a, ...rest, b] = [1, 2, 3]; // SyntaxErrorTại sao: Rest element phải là element cuối cùng trong pattern.
Cách nhận biết: SyntaxError ngay khi parse.
Cách xử lý: Đặt ...rest cuối cùng.
Destructuring không có declaration cần parentheses cho object
{ a } = { a: 1 }; // SyntaxError
({ a } = { a: 1 }); // ✅Tại sao: Parser hiểu { a } ở đầu câu là block statement, không phải object literal. Cần bọc trong () để force expression context.
Cách nhận biết: SyntaxError unexpected token =.
Cách xử lý: Thêm parentheses: ({ a } = obj).
10. Debug Lab (Bài lab gỡ lỗi)
Symptom (Triệu chứng): App crash khi API trả về user chưa có profile.
function getTheme(user) {
const { profile: { settings: { theme } } } = user;
return theme;
}
const userA = {
profile: { settings: { theme: "dark" } }
};
console.log(getTheme(userA)); // "dark" ✅
const userB = { profile: {} };
console.log(getTheme(userB));
// TypeError: Cannot destructure property 'theme' of 'undefined'Reproduction (Tái hiện lỗi): Chạy code với userB.
Evidence (Bằng chứng):
userB.profiletồn tại nhưnguserB.profile.settingslàundefined.- Destructuring cố gắng truy cập
undefined.theme.
Hypothesis (Giả thuyết): Nested destructuring profile: { settings: { theme } } giả định profile.settings tồn tại. Khi settings là undefined, JavaScript không thể destructuring tiếp.
Verification (Xác minh):
console.log(userB.profile.settings); // undefinedRoot Cause (Nguyên nhân gốc rễ): Destructuring nested không tự động "bail out" khi intermediate level missing. Nó cố gắng access property trên undefined.
Fix (Sửa):
function getTheme(user) {
const { profile: { settings: { theme } = {} } = {} } = user;
return theme;
}Hoặc an toàn hơn:
function getTheme(user) {
if (!user?.profile?.settings) return "light";
return user.profile.settings.theme;
}Prevention (Phòng ngừa):
- Khi destructuring nested từ API response, luôn hỏi: "Level trung gian có thể missing không?"
- Cung cấp default object cho mỗi level:
{ level1: { level2: { x } = {} } = {} }. - Hoặc dùng optional chaining (ES2020) khi environment cho phép — nhưng ở Stage 0, guard clause hoặc default object là cách hiểu rõ mechanism.
11. Design Exercise (Bài tập thiết kế giải pháp)
Bạn cần viết function nhận config object.
function setup({ host, port, db, cache, logger, retry, timeout }) {
connectDB(db);
initCache(cache);
setupLogger(logger);
// ... 20 lines later
if (timeout > 0) setTimeout(retry, timeout);
}function setup(config) {
const { host, port } = config;
initServer(host, port);
const { db } = config;
connectDB(db);
const { timeout, retry } = config;
if (timeout > 0) setTimeout(retry, timeout);
}Câu hỏi:
- Option A có lợi gì về readability?
- Option B có lợi gì khi một số property có thể missing?
- Nếu
configcó 15 properties nhưng function chỉ dùng 4, Option A có vấn đề gì?
[Đáp án tham khảo]
Bạn nghĩ:
- Option A: Nhìn vào đầu function là biết toàn bộ dependencies. Self-documenting. Dễ so sánh với function signature.
- Option B: Nếu
dbmissing, lỗi chỉ xảy ra khi đến dòngconnectDB. Dễ bọc try/catch cục bộ. Không throw ngay khi vào function nếu property unused missing (thực ra destructuring missing property chỉ làundefined, không throw — nhưng nếu nested thì throw). - Option A với 15 properties dài và nói "function cần nhiều thứ" có thể là smell — function làm quá nhiều. Nên nhóm config lại hoặc tách function.
Kết luận: Destructure ở top cho function nhỏ, clear. Destructure khi cần cho function lớn, defensive, hoặc khi property có thể nested missing.
12. Production Scenario (Tình huống thực tế)
Context: API user profile:
const user = {
id: 1,
name: "Alice",
preferences: {
notifications: { email: true, sms: false }
}
};Code hiện tại:
function shouldNotify(user, channel) {
const { preferences: { notifications } } = user;
return notifications[channel];
}Symptom: Khi user mới đăng ký chưa cài đặt preferences, user.preferences là undefined. App crash: Cannot destructure property 'notifications' of 'undefined'. Hoặc khi backend thêm field preferences: null.
Constraint: Không thể thay đổi API. Phải handle cả preferences missing, notifications missing, và channel missing.
Câu hỏi:
- Tại sao code crash với user mới?
- Viết lại dùng destructuring an toàn với default ở mỗi level.
- Nếu
channelkhông tồn tại trongnotifications, function nên trả về gì?
[Đáp án tham khảo]
Bạn nghĩ:
user.preferenceslàundefinedvới user mới. Destructuringpreferences: { notifications }cố accessundefined.notifications.- js
function shouldNotify(user, channel) { const { preferences: { notifications } = {} } = user || {}; if (!notifications) return false; return notifications[channel] || false; } - Nên trả về
false(default opt-out) hoặc giá trị default tùy business logic. Không nên throw.
Nâng cao (Awareness — Stage 2): Nếu đã học computed property destructuring và nullish coalescing:
jsfunction shouldNotify(user, channel) { const { preferences: { notifications: { [channel]: enabled } = {} } = {} } = user; return enabled ?? false; }Bài học: Destructuring nested từ external data (API) luôn cần defensive defaults. Đừng giả định shape cố định.
13. AI-assisted Exercise (Bài tập với AI)
Level B — Challenge
- Tự trả lời trước: Viết đoạn code destructuring với default value. Dự đoán output khi property là
null.jsconst user = { role: null }; const { role = "guest" } = user; console.log(role); - Hỏi AI: "Tại sao
rolelànullthay vì"guest"? Tôi đã đặt default value mà?" - So sánh câu trả lời AI với nhận định của bạn. AI có nhấn mạnh rằng default trong destructuring chỉ kích hoạt với
undefined, không phảinull? - Verify bằng MDN: tìm "Destructuring assignment" trên MDN, đọc phần "Default values".
Gợi ý
AI thường biết câu trả lời đúng nhưng đôi khi giải thích mơ hồ bằng cách nói "null is a value, undefined means missing". Nếu AI không chỉ ra rằng đây là quy tắc cốt lõi của destructuring spec — default chỉ trigger khi property evaluate to undefined — bạn đã tìm ra điểm mù. AI cũng có thể nhầm lẫn với function parameter default (cũng chỉ undefined).
Đáp án tham khảo
Bạn nghĩ:
rolelànullvì default value trong destructuring chỉ kích hoạt khi property làundefined.nulllà giá trị explicit, không phải "missing". Quy tắc này giống function parameter default.AI trả lời (typical):
- Default values in destructuring only apply when the property is
undefined. nullis an assigned value, so the default does not apply.- The result is
null.
- Default values in destructuring only apply when the property is
So sánh: AI thường đúng về behavior nhưng đôi khi không giải thích tại sao điều này quan trọng trong production: nếu API trả về
{ role: null }(explicit "no role") thì default không nên kích hoạt — đó là intent đúng. Nhưng nếu developer nghĩ default sẽ cover cảnull, họ sẽ có bug.Điểm AI nói sai hoặc quá mơ hồ: "null is a value" — đúng nhưng chưa đủ. AI hiếm khi nói rõ: "Nếu bạn cần xử lý cả null và undefined, bạn phải dùng logic sau destructuring:
const finalRole = role ?? 'guest'(nullish coalescing). Destructuring default không thay thế được."Kết luận: Nếu bạn chỉ ra được rằng destructuring default và nullish coalescing (
??) là hai cơ chế khác nhau cho hai use case khác nhau, bạn đã hiểu sâu hơn AI. Concept này sẽ quay lại ở Stage 1 (Function default parameters), Stage 6 (TypeScript optional properties), và Stage 8 (React default props pattern).
14. Teach Back (Dạy lại)
Giả sử một junior developer hỏi bạn:
"Anh/chị ơi,
const name = user.namevớiconst { name } = usercó gì khác nhau đâu? Em thấy cái thứ hai chỉ là viết tắt thôi mà? Tại sao người ta bảo dùng destructuring 'tốt hơn'?"
Hãy giải thích trong 2 phút, dùng đúng terminology: intent, shape declaration, default value, nested access.
Mô phỏng
- Bạn nói: Về cơ bản, destructuring là syntax để lấy property. Nhưng nó làm được nhiều hơn "viết tắt".
Thứ nhất — Intent: Khi bạn viết const { name, email } = user, bạn đang khai báo: "Function này cần name và email từ user." Đọc code là thấy shape. Còn const name = user.name nói về cơ chế: "Tôi đang truy cập property name."
Thứ hai — Default: const { role = "guest" } = user xử lý missing property trong một bước. Với dot notation bạn phải viết const role = user.role !== undefined ? user.role : "guest".
Thứ ba — Nested: const { profile: { name } } = user lấy user.profile.name mà không cần tạo biến trung gian const profile = user.profile.
Thứ tư — Function parameter: function greet({ name }) nói rõ function mong đợi object có name ngay từ signature.
💡 Tưởng tượng dot notation như mở từng ngăn kéo bằng tay. Destructuring như đưa cho bạn một checklist: "Tôi cần cái này, cái này, và cái này" — rồi tự động lấy ra.
Gợi ý đánh giá bản thân
- Đồng nghiệp có hiểu tại sao destructuring là "khai báo intent" không?
- Bạn có tránh được việc nói "nó chỉ là syntax sugar" không? (Nó là syntax sugar nhưng có semantics riêng về default và nested.)
- Nếu đồng nghiệp hỏi: "Vậy khi nào em không dùng destructuring?" — bạn trả lời được không? (Gợi ý: khi property name động, hoặc khi cần guard phức tạp trước khi access nested.)
- Nếu đồng nghiệp viết
{ a } = objvà bị SyntaxError — bạn giải thích được tại sao và sửa trong 5 giây không? (Gợi ý: cần parentheses({ a } = obj).)
15. Assessment (Đánh giá)
| Objective (Mục tiêu) | Hình thức đánh giá | Task |
|---|---|---|
| Object destructuring (Destructuring object) | Implementation (Thực hành) | Implementation Lab Level 1 |
| Array destructuring (Destructuring array) | Implementation (Thực hành) | Implementation Lab Level 3 |
| Default values (Giá trị mặc định) | Prediction (Dự đoán) | Prediction Câu 1, 3 |
| Rename property (Đổi tên property) | Implementation (Thực hành) | Implementation Lab Level 3 |
| Nested destructuring (Destructuring lồng nhau) | Implementation (Thực hành) | Implementation Lab Level 2–3 |
| Handle null/undefined source (Xử lý null/undefined) | Debug Lab | Debug Lab Section |
| Distinguish undefined vs null for defaults (Phân biệt undefined/null) | AI-assisted | AI-assisted Section |
| Explain intent vs mechanism | Teach Back | Teach Back Section |
16. Exit Criteria (Tiêu chí qua bài)
- [ ] Có thể sử dụng object destructuring để trích xuất nhiều property trong một câu lệnh.
- [ ] Có thể sử dụng array destructuring để trích xuất phần tử theo vị trí, bao gồm skip và rest.
- [ ] Có thể áp dụng default values trong destructuring và biết chỉ kích hoạt với
undefined. - [ ] Có thể đổi tên property trong destructuring (
oldName: newName). - [ ] Có thể viết nested destructuring đến 2 cấp.
- [ ] Có thể nhận diện khi destructuring sẽ throw (source là
null/undefined). - [ ] Có thể debug lỗi nested destructuring khi intermediate level missing.
- [ ] Có thể sử dụng destructuring trong function parameters để khai báo expected shape.
17. Spiral Connection (Liên kết xoắn ốc)
Previous (Trước): Object Utilities (0.6.6) — bạn đã biết chuyển object ↔ array bằng
Object.entries. Giờ bạn học cách "mở" object/array để lấy dữ liệu một cách declarative.
Current (Hiện tại): Destructuring — object/array unpacking, default values, rename, nested, rest. Khai báo intent qua shape.
Next (Tiếp theo):
- 0.6.8 (Spread & Shallow Copy) — Spread
...là "chiều ngược lại" của destructuring: gom lại thay vì mở ra.{ ...obj }tạo shallow copy. Kết hợp destructuring + spread để update object immutably.- Stage 1 (Execution Model) — Parameter binding: tại sao
function({ name })hoạt động? Destructuring là syntax sugar cho một loạtGetValueoperations trong execution context.- Stage 6 (TypeScript) — Tuple destructuring:
const [a, b]: [string, number] = arr. Object destructuring với type annotations.- Stage 8 (React) — Props destructuring là pattern bắt buộc:
function Button({ label, onClick }). Default props qua destructuring default. Spread props:<Button {...props} />.