Give fields local names
Destructuring takes values out of a record: const { title, pages } = book means declare title from book.title and pages from book.pages. It does not remove those properties or clone nested objects. In const { title: label } = book, title is the field name and label is the new local variable.
A default such as pages = 0 applies only when the value is undefined. It does not replace null. Missing data and explicitly empty data may require different rules. Do not use a convenient default to hide a required field that should have caused rejection.
Ask whether something is missing
Optional chaining, book.details?.pages, returns undefined when details is null or undefined rather than reading a property from an absent object. It does not validate that a present value has the correct type. value ?? fallback supplies the fallback only for null or undefined. Unlike value || fallback, it preserves meaningful zero, false, and empty text.
Read a compact expression in stages: look up the optional field, decide whether it is absent, then choose the display value. These operations are useful when optional data is genuinely optional. A required book id will still need explicit validation in the next lessons.
The ?. guards only the value immediately before it: book.details?.pages permits missing details but still assumes book is a record. To permit a missing book too, use book?.details?.pages. Optional chaining cannot rescue an undeclared variable name. Keep the expected input contract explicit.
Predict and trace
Write the output before running. Follow the values through each call; if your prediction differs, identify the first step that surprised you.
const book = { title: "Notes", pages: 0, details: null };
const { title: label, pages = 99 } = book;
console.log(label);
console.log(pages ?? 99);
console.log(pages || 99);
console.log(book.details?.author ?? "Unknown");Check your prediction
Notes
0
99
UnknownZero is present. The || expression replaces it because zero is falsy; ?? does not.
Separate absence from a meaningful zero
A destructuring default is applied when the property is undefined. A nullish default is applied for null or undefined. Neither one should automatically replace false, zero or empty text. These distinctions are useful only when you have decided which values the domain permits.
Renaming while destructuring changes the local name, not the original property. A nested value is still a shared reference. Destructuring makes access convenient; it is not validation or a copy policy.
const source = { pages: 0, title: "Types" };
const { title: label, pages = 99 } = source;
console.log(label, pages);
console.log(source.title);
console.log(source.label);Check your prediction
Types 0
Types
undefined The field remains title on source. The default does not replace zero. Reading source.label shows why a local rename should not be mistaken for changing the record schema.
const source = { note: null, pages: 0 };
const { note = "default" } = source;
console.log(note);
console.log(source.note ?? "fallback");
console.log(source.pages || 99);
console.log(source.pages ?? 99);Check your prediction
null
fallback
99
0 Destructuring leaves explicit null intact, while ?? chooses the fallback. || also replaces zero, which can silently change a legitimate zero-page result.
Try the rule on new inputs
Test a missing property, explicit undefined, null, zero and empty text. Write down which operation changes each one. Do not combine defaults until you can explain the policy at each stage.
Build it yourself
Destructuring & Optional Values: practise
Write pageLabel(book). Use the optional details.pages field, default to “unknown” only when absent, and return text. Print labels for zero pages and absent details.
// Expected: Pages: 0, then Pages: unknownHint 1: the idea
Do not confuse a zero value with a missing field.
Hint 2: a first step
Read book.details?.pages and use ?? before formatting.
Show one solution
function pageLabel(book) {
const pages = book.details?.pages ?? "unknown";
return `Pages: ${pages}`;
}
console.log(pageLabel({ details: { pages: 0 } }));
console.log(pageLabel({}));Pages: 0
Pages: unknownTry null details and pages: null. Then try pages: “many”: it remains present, proving this helper formats rather than validates.
Test a changed requirement
Try null details and pages: null. Then try pages: “many”: it remains present, proving this helper formats rather than validates.
Explain before moving on
Explain the difference between a destructuring default and ??. Why is optional chaining not a schema check?
Completion is saved in this browser only. It does not measure mastery.