Frontend Master

JavaScript Curriculum

Everything Together
+100 XP

Everything Together

hard
~35 min·100 XP

This is the chapter final. A real-world JavaScript program — not a toy — that wires every concept you've learned into something that does meaningful work. When you finish, you'll have written code that looks like the code in production Nexus, styled to the same standards, tested against the same criteria.

Nineteen lessons. One program.

Every feature of Chapter 01 JavaScript was introduced in isolation — a concept, a component, a small challenge. This lesson asks you to use them together, the way you'll use them in every real project you work on.

Here's the map of everything you've learned and how it connects:

chapter 01 — all 19 concepts and how they connect

Click any concept to see what it depends on and what it unlocks.

Click each concept to see what it depends on and what it unlocks. The capstone sits at the bottom of the graph — it depends on everything.


What you're building

A UserRegistry — a class-based system that manages a list of users with validation, functional processing, regex-based name checking, and localStorage persistence.

This is not a contrived exercise. Every element maps directly to a real-world pattern:

FeatureLessonReal-world analog
Class with #users16Entity repositories, data models
Input validation with throw10API request validation
Regex name check18Form field validation
Sort + filter + map chain17Dashboard data processing
JSON.stringify to localStorage19Settings persistence, offline cache
Static factory from storage15/16Hydration from persisted state
Optional chaining + ??13Safe config and data access

Architecture walkthrough

Before you write the code, read the structure:

js
class UserRegistry { #users = [] // Private — can't be accessed from outside // Add a user — two validation layers before accepting add(user) { // 1. Structural validation — has required fields, right types if (!user || typeof user.name !== 'string' || typeof user.score !== 'number' || user.score < 0) { throw new Error('Invalid user') } // 2. Name format validation — regex if (!/^[a-zA-Z\s]{2,}$/.test(user.name.trim())) { throw new Error('Invalid name') } this.#users.push({ name: user.name.trim(), score: user.score }) } // Functional pipeline: sort → slice → map getTopUsers(n) { return [...this.#users] .sort((a, b) => b.score - a.score) .slice(0, n) .map(u => `${u.name} (${u.score})`) } // Persist: JSON.stringify the private array saveToStorage(key) { localStorage.setItem(key, JSON.stringify(this.#users)) } // Static factory: load, parse, validate, re-populate static loadFromStorage(key) { const registry = new UserRegistry() try { const raw = localStorage.getItem(key) const data = raw ? JSON.parse(raw) : [] data.forEach(entry => { try { registry.add(entry) } catch { /* skip invalid */ } }) } catch { // storage read or JSON parse failed — return empty registry } return registry } }

Key patterns explained

Private fields keep state safe

js
#users = [] // From outside: registry.#users // SyntaxError — private, enforced by the engine registry.getTopUsers(3) // the only sanctioned way to read it

Two-layer validation — structural then semantic

js
// Layer 1: does it have the right shape? if (typeof user.score !== 'number' || user.score < 0) throw new Error('Invalid user') // Layer 2: does the content meet business rules? if (!/^[a-zA-Z\s]{2,}$/.test(user.name.trim())) throw new Error('Invalid name')

The two layers are separated because they're different kinds of errors — structural failure vs business-rule failure. Callers can catch them separately if needed.

Functional pipeline in a method

js
getTopUsers(n) { return [...this.#users] // copy — never mutate the private array .sort((a, b) => b.score - a.score) .slice(0, n) // take only the first n .map(u => `${u.name} (${u.score})`) }

slice(0, n) after sort takes the top n. The spread copy protects the private array from sort's in-place mutation.

Static factory method — restoring state

js
static loadFromStorage(key) { const registry = new UserRegistry() // ... populate it ... return registry } // Called on the class, not an instance: const restored = UserRegistry.loadFromStorage('my-users')

This is the factory pattern — a static method that constructs and returns an instance with a specific setup. Cleaner than putting complex initialisation logic in a constructor.


Putting it together — complete test

js
// Build a registry const reg = new UserRegistry() reg.add({ name: 'Alex Chen', score: 95 }) reg.add({ name: 'Jordan', score: 72 }) reg.add({ name: 'Sam', score: 88 }) reg.add({ name: 'Mia', score: 60 }) // Try to add invalid entries try { reg.add({ name: '1Alex', score: 50 }) } catch(e) { console.log(e.message) } // "Invalid name" try { reg.add({ name: 'Bob', score: -10 }) } catch(e) { console.log(e.message) } // "Invalid user" // Functional query reg.getTopUsers(2) // ['Alex Chen (95)', 'Sam (88)'] // Persist and restore reg.saveToStorage('nexus-users') const restored = UserRegistry.loadFromStorage('nexus-users') restored.getTopUsers(2) // ['Alex Chen (95)', 'Sam (88)'] — same result

This is what JavaScript looks like in production

Classes encapsulate data and behaviour. Private fields prevent accidental mutation. Validation throws meaningful errors. Functional pipelines express transformations clearly. Static factories restore state from persistence. Regex handles format validation inline.

None of this is exotic. All of it is expected. Chapter 01 is complete.

Challenge

Build a UserRegistry class with: a #users private field (array). An add(user) method that validates the user object has name (string) and score (number ≥ 0) — throws 'Invalid user' if not. Uses regex /^[a-zA-Z\\s]{2,}$/ to validate that name contains only letters and spaces (min 2 chars) — throws 'Invalid name' if not. A getTopUsers(n) method that returns the top n users sorted by score descending, mapped to 'name (score)' strings. A saveToStorage(key) method that JSON.stringifies the users array into localStorage. A static loadFromStorage(key) method that reads from localStorage, parses the JSON, re-validates each entry, and returns a new UserRegistry populated with the valid entries (skipping invalid ones silently). Test: create a registry, add at least 3 users, call getTopUsers(2), save to storage, load back and verify.

capstoneclassesprivate-fieldsregexvalidationfunctional-programmingerror-handlinglocalStorageclosuresasyncmodern-syntax
Everything Together | Nexus Learn