Checkpoint: Modern JavaScript
Reviewed & published by Brayan K
A checkpoint is a hands-on review that combines everything from the modern JavaScript track — template literals, optional chaining, array and object methods, symbols, getters/setters, Proxy, and BigInt — into one build challenge and a short quiz.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
No new syntax here: this is where the pieces click together into something you could ship.
What You'll Practice in This Checkpoint
- Recall every modern-JS concept
- Combine array & object methods
- Use optional chaining for safe reads
- Wrap data in a validating Proxy
- Build a small processing utility
- Self-check with a quiz
📋 What You've Learned
Here's the whole modern-JavaScript toolkit in one place. Each row links the idea to a one-line reminder.
| Concept | One-line reminder |
|---|---|
| Template literals | `hi ${name}` — interpolation, multiline, tags |
| Optional chaining / ?? | a?.b ?? def — safe reads + null-only defaults |
| Array methods | find, some, flatMap, toSorted |
| Object methods | entries, fromEntries, freeze, groupBy |
| Symbols | Symbol() — unique keys & Symbol.iterator |
| Getters / setters | get/set + descriptor flags |
| Proxy & Reflect | intercept ops with traps; forward via Reflect |
| BigInt | 10n — exact integers past the safe limit |
🛠️ Build Challenge — A Mini Order Processor
Build a small utility that (1) reads each order's nested customer city safely with optional chaining, (2) groups orders by status using Object.groupBy, (3) finds the highest-value order with an array method, and (4) wraps a config object in a validating Proxy that rejects negative discounts. Fill in the blanks in the starter, then check against the full solution.
const orders = [
{ id: 1, status: "paid", total: 90, customer: { city: "Lisbon" } },
{ id: 2, status: "open", total: 40, customer: null },
{ id: 3, status: "paid", total: 120, customer: { city: "Berlin" } },
];
// 1) Safe city read with a default — fill in the operators
const cities = orders.map(o => o.customer?.city ___ "Unknown");
console.log(cities); // ✅ Expected output: [ 'Lisbon', 'Unknown', 'Berlin' ]
// 2) Group by status — fill in the method
const byStatus = Object.___(orders, o => o.status);
console.log(Object.keys(byStatus)); // ✅ Expected output: [ 'paid', 'open' ]
// 3) Highest-value paid order — fill in the array method
const topPaid = byStatus.paid.___((a, b) => b.total - a.total)[0];
console.log(topPaid.id); // ✅ Expected output: 3
// 4) Validating Proxy for config — reject negative discount
const config = new Proxy({}, {
set(t, k, v) {
if (k === "discount" && v < 0) throw new RangeError("no negative discount");
return Reflect.___(t, k, v);
},
});
config.discount = 10;
console.log(config.discount); // ✅ Expected output: 10Notice how four separate lessons cooperate: ?. + ??, Object.groupBy, the immutable toSorted, and a validating Proxy with Reflect.set.
✅ Run the Finished Utility
Here is the completed solution as one runnable program, plus a template-literal report at the end. Run it to confirm every piece works together.
📝 Checkpoint Quiz
Answer each in your head, then reveal to check.
The nullish coalescing operator ??. Unlike ||, it only falls back for null and undefined, so a real 0 is preserved.
sort mutates the array in place; toSorted returns a new sorted array and leaves the original untouched.
Object.fromEntries(Object.entries(obj).map(...)) — convert to pairs, map them, then rebuild.
Symbol.for returns the same shared symbol from the global registry every time, while Symbol("x") always creates a new, unequal symbol.
Call Reflect.set(target, key, value) and return its result — that performs the default assignment and returns true.
JavaScript refuses to mix BigInt and Number. Convert first: 10n + BigInt(5) or Number(10n) + 5.
Pitfalls to Avoid
- 1️⃣ Defaulting with || when 0/"" are valid
- 2️⃣ Mutating shared data with sort
- 3️⃣ Forgetting Reflect.set's return in a trap
Quick Reference — Pick the Right Tool
| Need | Reach for |
|---|---|
| One matching item | find |
| Safe nested read | ?. + ?? |
| Bucket by key | Object.groupBy |
| Cross-cutting validation | Proxy + Reflect |
| Exact huge integer | BigInt |
📚 Keep Learning
- MDN: JavaScript Guide
- MDN: JavaScript Reference
- MDN: Expressions and operators
🎉 Checkpoint Complete — Modern JavaScript!
- ✅ You recalled the full modern-JS toolkit
- ✅ You combined optional chaining, array/object methods, and a Proxy in one utility
- ✅ You can pick the right tool for a given need
- ✅ You self-checked with the quiz
Practice quiz
Which operator keeps a value of 0 but replaces undefined?
- || (logical OR)
- ?. (optional chaining)
- ?? (nullish coalescing)
- && (logical AND)
Answer: ?? (nullish coalescing). ?? only falls back for null and undefined, so a real 0 is preserved; || would replace it.
What is the difference between sort and toSorted?
- sort mutates in place; toSorted returns a new array
- They are identical
- toSorted mutates; sort returns a copy
- toSorted only works on numbers
Answer: sort mutates in place; toSorted returns a new array. sort reorders the original array; toSorted leaves it untouched and returns a sorted copy.
What does Object.fromEntries(Object.entries({a:1,b:2}).map(([k,v]) => [k, v*10])) produce?
- {a:1, b:2}
- [[a,10],[b,20]]
- {a:11, b:12}
- {a:10, b:20}
Answer: {a:10, b:20}. entries to pairs, map each value times 10, then fromEntries rebuilds: {a:10, b:20}.
Why use Symbol.for("x") instead of Symbol("x")?
- Symbol.for is faster
- Symbol.for returns the same shared symbol every time
- Symbol("x") is deprecated
- There is no difference
Answer: Symbol.for returns the same shared symbol every time. Symbol.for pulls from a global registry, so equal keys match; Symbol("x") always makes a new unequal symbol.
Inside a Proxy set trap, how do you perform the actual write?
- return Reflect.set(target, key, value)
- target[key] = value
- return true
- delete target[key]
Answer: return Reflect.set(target, key, value). Reflect.set forwards the default assignment and returns the boolean the trap must return.
What happens when you evaluate 10n + 5?
- 15n
- 15
- It throws a TypeError
- "105"
Answer: It throws a TypeError. JavaScript refuses to mix BigInt and Number; convert first, e.g. 10n + BigInt(5).
What does Object.groupBy(orders, o => o.status) return for statuses paid, open, paid?
- An array of statuses
- An object keyed by status with arrays of orders
- A Set of statuses
- A Map of counts
Answer: An object keyed by status with arrays of orders. Object.groupBy buckets items into an object whose keys are the returned group strings.
Which array method returns the FIRST element matching a condition?
- filter
- some
- map
- find
Answer: find. find returns the first matching element (or undefined); filter returns all matches as an array.
After Object.freeze({a:1}), what does assigning obj.a = 2 then reading obj.a give (non-strict)?
- 2
- 1
- undefined
- It throws
Answer: 1. freeze blocks the write; the value stays 1 (the assignment is silently ignored in non-strict mode).
What does [1, 2].flatMap(n => [n, n * 2]) produce?
- [[1,2],[2,4]]
- [1, 2, 4]
- [1, 2, 2, 4]
- [2, 4]
Answer: [1, 2, 2, 4]. flatMap maps each element to an array then flattens one level: [1, 2, 2, 4].
Continue this course
- Previous: BigInt & Number Precision
- Next: Promise Combinators (all, race, allSettled, any) — Coordinate multiple async operations and handle partial failures
- Quick reference: JavaScript cheat sheet
Frequently asked questions
What does this checkpoint cover?
It pulls together the modern JavaScript track: template literals, optional chaining and nullish coalescing, the essential array methods, object methods, symbols, getters and setters, Proxy and Reflect, and BigInt. The build challenge combines several of them in one realistic utility.
How should I use the build challenge?
Try the starter version first, filling in the blanks yourself. Run it, read the errors, and iterate. Only open the full solution once you have made a genuine attempt — comparing your working code to the reference is where most of the learning happens.
Do I need to memorize every method?
No. The goal is to recognize which tool fits a problem — find for one item, filter for many, ?? for safe defaults, a Proxy for cross-cutting validation. You can always look up exact signatures; what matters is reaching for the right concept.