8 exercises for every chapter — from simple warm-ups to real-world challenges. Work through them in the Playground after studying each chapter. Every exercise has clear success criteria so you know exactly when you have got it right.
Practice declaring variables correctly, understanding when to use const vs let, and writing clear descriptive names. These habits matter from day one.
Declare variables to describe yourself. Use const for things that will not change, and let for things that might.
const)let — it will change next year)const)let)var used anywhereProve to yourself that const prevents reassignment.
const schoolName = 'AngelCode Labs'schoolName = 'Other School'try/catch block and log the error messagelet variable and successfully reassign ittry/catch catches a TypeErrorlet variable reassigns successfully without any errorRewrite these poorly named variables with clear, descriptive camelCase names:
let x = 'Accra' → should describe a citylet n = 25 → should describe someone's agelet f = true → should describe whether a form was submittedlet d = new Date() → should describe the current dateBuild a simple receipt calculator using variables.
const variables: itemName (string), unitPrice (number), quantity (number)subtotal, tax (15% of subtotal), totalunitPrice or quantity automatically updates all calculated valuesSwap the values of two variables — first the old way (using a temporary variable), then the modern way.
let a = 'first' and let b = 'second'temp to swap them. Log the result.[a, b] = [b, a]. Log the result.Simulate a vote counter for three candidates.
let variables for three candidates, each starting at 0++ and +=)++ or += — not direct assignmentUnderstand how block scope works with let and const.
const city = 'Accra' outside any blockif (true) { } block, declare let region = 'Greater Accra'city from inside the block — it worksregion from inside the block — it worksregion from outside the block — wrap in try/catch and log the errorcity accessible both inside and outside the blockregion accessible only inside the blockBuild a complete student profile using only variables — no objects or arrays yet.
yearsRemaining (4 minus current year), isHonours (GPA above 3.5)Explore all six primitive types and learn how to check, convert, and work with them safely. Understanding types is what prevents the most common JavaScript bugs.
Use typeof to check the type of every value listed below and log the result.
'Hello', 42, true, undefined, null, {}, [], function(){}null and [] — they are surprisesA user types their age into a form. It arrives as a string. Show the problem and fix it.
const userInput = '25'userInput + 5 — log the result and explain whyNumber(), then add 5 — log the correct resultNumber('hello') and how to check for that'25' + 5 produces '255' (string concatenation)Number('25') + 5 produces 30Number('hello') produces NaNisNaN(Number('hello')) correctly returns trueTest each value and log whether it is truthy or falsy using an if statement.
0, 1, '', 'hello', null, undefined, false, true, NaN, [], {}[] and {} will surprise you[] and {} are both truthy (empty objects and arrays are truthy)Demonstrate the difference between undefined and null in a real scenario.
let selectedProduct without a value — log it (undefined: nothing chosen yet)null — log it (null: user deliberately cleared their selection)undefined == null (true) vs undefined === null (false) and explain whyhasValue(x) that returns true only if x is neither null nor undefinedhasValue(0) returns true (0 is a valid value)hasValue(null) returns falsehasValue(undefined) returns falsehasValue('') returns true (empty string is a valid value)Write a function safeNumber(input) that converts any input to a number safely.
NaN, return 0 as a defaultnull or undefined, return 0'42', 'hello', null, undefined, true, '', '3.14'safeNumber('42') → 42safeNumber('hello') → 0safeNumber(null) → 0safeNumber(true) → 1safeNumber('3.14') → 3.14Format prices correctly for display on a Ghana e-commerce site.
formatPrice(amount) that takes a number and returns a string like ₵45.00.toFixed(2) for the decimal formatting45, 45.5, 45.999, 'hello', nullformatPrice(45) → '₵45.00'formatPrice(45.999) → '₵46.00' (rounds up)formatPrice('hello') → '₵0.00'Write a set of type-checking utility functions used in real applications.
isString(x) — returns true only for real stringsisNumber(x) — returns true only for real numbers (not NaN)isBoolean(x) — returns true only for booleansisArray(x) — returns true only for arrays (not objects)isNumber(NaN) → false (NaN is not a usable number)isArray([]) → true, isArray({}) → falseisString(42) → falsenull and undefined without crashingBuild a function that validates a registration form submission.
validateForm(data) where data is an object: { name, age, email, agreeToTerms }true (boolean){ valid: true/false, errors: [] }{ valid: true, errors: [] }'25' (string) fails — must be a numberagreeToTerms: 1 fails — must be boolean true, not number 1Practice arithmetic, comparison, and logical operators. Focus especially on the difference between == and === — getting this wrong causes bugs that are very hard to find.
Calculate the following and log each result with a description.
Math.floor)%)**)+=Demonstrate why == is dangerous and === is safe.
0 == false, 0 === false'' == false, '' === falsenull == undefined, null === undefined'5' == 5, '5' === 5== comparison has a comment explaining the coercion that happened===Model a cinema ticket pricing system using logical operators.
isStudent, isWeekend, isMember, ageisStudent AND age is under 25isWeekend is trueisMember is trueUse the nullish coalescing operator ?? to provide safe defaults.
getDisplayName(user) that returns user.name ?? 'Guest'?? is better than || when the value could legitimately be 0 or ''const score = 0; const display = score || 'No score' — what is the problem?const display = score ?? 'No score' — what is the result now?getDisplayName({ name: 'Ama' }) → 'Ama'getDisplayName({ name: null }) → 'Guest'0 || 'No score' → 'No score' (wrong — 0 is a valid score)0 ?? 'No score' → 0 (correct)Use optional chaining ?. to safely access deeply nested data.
const order = { customer: { name: 'Kwame', address: { city: 'Kumasi' } } }order.customer.address.city safely using ?.order.customer.phone.number without ?. — catch the error?. — it returns undefined instead of crashing?? to provide a fallback: order.customer?.phone?.number ?? 'No phone'?.: TypeError: Cannot read properties of undefined?.: undefined (no crash)?. ??: 'No phone'Write a grade classifier using the ternary operator.
classify(score) using a ternary chainUse short-circuit evaluation for common patterns seen in real code.
const greeting = userName || 'Guest' — log when userName is '' vs 'Ama'isLoggedIn && showDashboard() — call the function only when logged inconfig.timeout ??= 3000 — only set if currently null/undefineduser.role &&= user.role.toUpperCase()'' || 'Guest' → 'Guest''Ama' || 'Guest' → 'Ama'showDashboard() only called when isLoggedIn is true??= does not overwrite an existing value of 0Build a full shopping cart price engine using operators.
subtotal, isMember, couponCode, isWeekendisMembercouponCode === 'SAVE20' apply an additional 20% off the discounted priceisWeekendPractice making decisions and repeating code. These are the tools that make programs actually useful — without them everything runs the same way every single time.
Write an age verification function for a website.
checkAccess(age)if / else if / else not switchUse a switch statement to describe each day.
describeDay(day) where day is 1–7 (1 = Monday)describeDay(8) returns 'Invalid day'break except the fall-through onesUse a for loop to log numbers with labels.
Generate a multiplication table using nested loops.
for loops — outer for rows (1–10), inner for columns (1–10)Write a password strength checker using control flow.
checkPassword(pw){ strength, score, feedback }checkPassword('abc') → Weak, score 0checkPassword('Password1') → Medium, score 3checkPassword('P@ssword1!') → Strong, score 4Simulate an ATM withdrawal system using a while loop.
while loop to process an array of withdrawal amounts: [100, 200, 150, 300, 50]breakDraw a number pyramid using nested loops and string building.
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5
for loop for rows, a nested loop to build the number sequence, and string padding for alignmentProcess an array of student objects and generate a full class report.
const students = [ { name: 'Ama', scores: [78, 82, 91] }, { name: 'Kofi', scores: [55, 60, 48] }, { name: 'Abena', scores: [90, 95, 88] }, { name: 'Kwame', scores: [70, 65, 72] }, ];
for...of loop, continue to skip failed students in the honours countPractice writing clean, reusable functions. Focus on single responsibility — each function does exactly one thing. This chapter also covers arrow functions and default parameters.
Write four basic functions — two as declarations and two as arrow functions.
function square(n) — returns n × nfunction isEven(n) — returns true if n is evenconst cube = (n) => — returns n × n × nconst greet = (name) => — returns 'Hello, [name]!'square(7) → 49isEven(4) → true, isEven(7) → falsecube(3) → 27greet('Kwame') → 'Hello, Kwame!'Write functions that use default parameters so they work even when arguments are missing.
createProduct(name, price = 0, currency = 'GHS') — returns a formatted stringsendEmail(to, subject = 'No Subject', body = '') — logs a simulated emailrepeat(str, times = 1) — returns the string repeated that many timescreateProduct('Kente') → uses default price ₵0 and currency GHSrepeat('ha') → 'ha' (once)repeat('ha', 3) → 'hahaha'Practice using return values by chaining function calls.
celsiusToFahrenheit(c) — formula: (c × 9/5) + 32fahrenheitToCelsius(f) — formula: (f − 32) × 5/9roundTo2(n) — rounds to 2 decimal placescelsiusToFahrenheit(0) → 32celsiusToFahrenheit(100) → 212roundTo2(fahrenheitToCelsius(celsiusToFahrenheit(100))) → 100Build a small maths utility library of arrow functions.
add(a, b), subtract(a, b), multiply(a, b), divide(a, b)divide should return 'Cannot divide by zero' if b is 0average(...nums) — uses rest parameters to accept any number of valuesclamp(value, min, max) — returns value clamped between min and maxdivide(10, 0) → 'Cannot divide by zero'average(10, 20, 30, 40) → 25clamp(150, 0, 100) → 100clamp(-5, 0, 100) → 0Practice passing functions as arguments — the foundation of callbacks.
applyTwice(fn, value) — applies fn to value, then applies fn to the resulttransform(numbers, fn) — applies fn to every item in an array and returns a new arrayapplyTwice(x => x * 2, 3) → should give 12transform([1,2,3,4], x => x * x) → should give [1,4,9,16]applyTwice(x => x + 10, 5) → 25transform([1,2,3], x => x * 3) → [3, 6, 9]Use closures to create private state — a fundamental pattern in JavaScript.
makeCounter(start = 0, step = 1)increment(), decrement(), reset(), value()counter.increment() three times then counter.value() → 3counter.count → undefined (private)makeCounter(10, 5).increment() → value is 15Write a pipeline of small functions that clean user input — one function per job.
trim(str) — removes leading and trailing whitespacelowercase(str) — converts to lowercaseremoveSpaces(str) — replaces all spaces with hyphenslimitLength(str, max = 50) — truncates to max characterssanitiseSlug(input) that chains all four in ordersanitiseSlug(' Hello World ') → 'hello-world'sanitiseSlug(' My Amazing Blog Post Title That Is Very Long Indeed ') is truncated at 50 charsBuild a flexible discount engine using functions that return functions.
makeDiscount(rate) — returns a function that applies that discount rate to any pricemakeFloorDiscount(rate, floor) — discount only applies if price is above the floorcomposeDiscounts(...discountFns) — applies all discounts in sequencemakeDiscount(0.10)(200) → 180makeFloorDiscount(0.20, 300)(250) → 250 (no discount — below floor)makeFloorDiscount(0.20, 300)(400) → 320Master the array methods you will use every day: map, filter, reduce, find, and forEach. These replace loops for most data processing tasks.
Create and manipulate a shopping list array.
push (end) and unshift (beginning)pop and store it in a variableUse map to transform an array of product prices.
const prices = [45, 120, 30, 89, 210];
withTax — all prices with 15% tax addeddiscounted — all prices with 10% removedlabels — each price formatted as '₵45.00'prices array must remain unchangedwithTax[0] → 51.75discounted[4] → 189labels[2] → '₵30.00'prices still equals [45, 120, 30, 89, 210]Filter a student list based on different criteria.
const students = [ { name: 'Ama', score: 78, passed: true }, { name: 'Kofi', score: 45, passed: false }, { name: 'Abena', score: 92, passed: true }, { name: 'Yaw', score: 55, passed: false }, { name: 'Efua', score: 88, passed: true }, ];
Use reduce to summarise an array of transactions.
const transactions = [ { type: 'credit', amount: 500 }, { type: 'debit', amount: 120 }, { type: 'credit', amount: 350 }, { type: 'debit', amount: 80 }, { type: 'debit', amount: 200 }, ];
reducereducePractice the search methods on a product array.
const products = [ { id: 1, name: 'Kente', price: 85, stock: 12 }, { id: 2, name: 'Batik', price: 60, stock: 0 }, { id: 3, name: 'Adinkra', price: 120, stock: 5 }, { id: 4, name: 'Smock', price: 200, stock: 3 }, ];
findsomeeveryfindIndexfind returns { id: 3, name: 'Adinkra', ... }some out of stock → trueevery above 50 → trueSort and paginate an array of products.
sliceproducts array is unchanged after all sortingProcess nested and duplicate data.
const tags = [ ['html', 'css', 'beginner'], ['css', 'flexbox', 'intermediate'], ['javascript', 'beginner', 'dom'], ];
flat()SetProcess a full product inventory using only array methods — no for loops.
const inventory = [ { name: 'Kente', category: 'fabric', price: 85, qty: 12 }, { name: 'Batik', category: 'fabric', price: 60, qty: 0 }, { name: 'Sandals', category: 'footwear',price: 150, qty: 8 }, { name: 'Basket', category: 'craft', price: 45, qty: 20 }, { name: 'Adinkra', category: 'fabric', price: 120, qty: 5 }, ];
reduce into an object: { fabric: [...], footwear: [...], craft: [...] }Objects are the core data structure of JavaScript. Every piece of data from a server arrives as an object. Practice creating, reading, modifying, and combining objects correctly.
Create a user profile object and access its properties.
firstName, lastName, age, email, isActivefullName() that returns the first and last name combinedgreet() that returns 'Hello, I am [fullName] and I am [age] years old.'email using dot notation and also bracket notationuser.fullName() → 'Ama Mensah'user.greet() → 'Hello, I am Ama Mensah and I am 22 years old.'user.email and user['email'] return the same valuePractice modifying objects by adding, updating, and deleting properties.
{ name: 'Kente', price: 85, category: 'fabric' }stock: 10category propertycategory still exists using the in operator{ name: 'Kente', price: 95, stock: 10 }'category' in product → false'stock' in product → trueUse spread syntax to copy and merge objects without mutating originals.
defaultSettings = { theme: 'dark', fontSize: 14, language: 'en' }userSettings = { theme: 'light', fontSize: 18 }{ theme: 'light', fontSize: 18, language: 'en' }defaultSettings.theme is still 'dark' after mergePractice object destructuring — extracting values cleanly.
const order = { id: 1042, customer: { name: 'Kwame', city: 'Kumasi' }, items: ['Kente', 'Adinkra'], total: 205, paid: true, };
id, total, and paid in one linecustomer.name with a rename: { customer: { name: customerName } }notes = 'None' (it does not exist in the object)formatOrder({ id, total, customer })customerName → 'Kwame'notes → 'None' (default applied)formatOrder(order) logs a string using all three destructured propertiesUse the Object static methods to iterate and transform an object.
const scores = { Ama: 78, Kofi: 92, Abena: 65, Yaw: 88 };
Object.keys()Object.values() and reduceObject.entries() and reduceObject.fromEntries + map{ Ama: 156, Kofi: 184, Abena: 130, Yaw: 176 }Work with deeply nested object data — the kind you get from a server.
const school = { name: 'AngelCode Academy', location: { city: 'Accra', region: 'Greater Accra' }, departments: { tech: { head: 'Mr Asante', students: 120 }, arts: { head: 'Ms Agyeman', students: 85 }, }, };
science: { head: 'Dr Boateng', students: 60 }Process an array of order objects — the most common real-world pattern.
const orders = [ { id: 1, customer: 'Ama', amount: 120, status: 'paid' }, { id: 2, customer: 'Kofi', amount: 85, status: 'pending' }, { id: 3, customer: 'Abena', amount: 200, status: 'paid' }, { id: 4, customer: 'Yaw', amount: 55, status: 'cancelled'}, ];
filter + mapreduceformattedAmount property (e.g. '₵120.00')formattedAmount propertyBuild a configuration system that merges settings at multiple levels.
defaults, envConfig (production overrides), userConfig (user preferences)theme, language, notifications, timeout, debuggetConfig(key) that reads from the merged config with a fallbackgetConfig('missing-key') returns a sensible default, not an errorThis is where JavaScript becomes visible. Practice selecting elements, changing content, adding classes, and building HTML dynamically — the skills used in every real web project.
Practice selecting elements and reading their content.
<h1 id="title">, three <p class="paragraph">, and a <button>textContentquerySelector and log its tag nameUse JavaScript to change what is displayed on the page.
<h1> and change its text to 'Updated by JavaScript'<p> and change its colour to #f0c040 using style.color<img> and change its src attribute using setAttributeplaceholder attributesrc valuePractice managing CSS classes from JavaScript.
<div id="box"> and CSS classes: .active (green border), .hidden (display none), .highlighted (yellow background)active class and check it is there with containsactive, add highlightedhidden twice — confirm box shows, then hideshighlighted with active using replacebox.classList.contains('active') → trueactive class, NOT highlightedBuild HTML dynamically using createElement.
<ul id="list"> in the HTML<li> elements, each with different text<li> should have a class of list-item<li> when clickedlist-item visible in DevToolsBuild a working dark mode toggle using DOM and classList.
.dark on <body> switches to dark background and light textdark class on body when the button is clickedlocalStorage and apply it on page loadRender an array of product objects as HTML cards on the page.
const products = [ { name: 'Kente Fabric', price: 85, inStock: true }, { name: 'Leather Sandals',price: 150, inStock: false }, { name: 'Woven Basket', price: 45, inStock: true }, ];
<div class="card"> with: name, price (formatted), and a badge that says In Stock or Out of Stock'createElement — no innerHTMLinnerHTML used anywhereNavigate the DOM tree using traversal properties.
<ul> and 5 <li> children<li> directly using querySelectorclosest('.container') to find the nearest ancestor with that class<li> is the <ul><li><ul> is the first <li>closest returns the correct ancestorquerySelector callsBuild a fully dynamic data table from a JavaScript array.
const data = [ { name: 'Ama', score: 78, grade: 'B' }, { name: 'Kofi', score: 45, grade: 'F' }, { name: 'Abena', score: 91, grade: 'A' }, ];
<thead> from the object keys of the first item<tbody> rows from each data itemcreateElement — no innerHTMLEvents are how users interact with your page. Practice attaching listeners, reading event data, and the important patterns: delegation, preventing defaults, and form handling.
Build a simple click counter with increment and reset buttons.
<span id="count">0</span>, a +1 button, and a Reset buttonShow a live preview of what the user types.
<p> below itinput eventHandle a form submission and validate the inputs before accepting them.
e.preventDefault() to stop the page reloadTrack the mouse position and update the UI in real-time.
mousemove event and read e.clientX and e.clientYUse event delegation to handle clicks on a list — even on items added later.
<ul> with 3 <li> items, each with a data-id attribute<ul> — not to individual <li> itemse.target.closest('li') to identify which item was clicked<li> — clicking the new item must also workdata-id of the clicked itemImplement keyboard shortcuts for a simple text editor area.
<textarea> that responds to key combinationsCtrl+B — wraps selected text in **bold**Ctrl+I — wraps selected text in _italic_Ctrl+K — wraps selected text in [link text](url)e.ctrlKey and e.key and always call e.preventDefault()Build a simple image gallery with keyboard and click navigation.
Build a drag-and-drop list using the HTML Drag and Drop API.
draggable="true"dragstart, dragover, drop eventsevent.dataTransfer.setDataString manipulation is used in almost every program. Practice template literals, all the common string methods, and building real output like receipts, reports, and formatted messages.
Rewrite these messy string concatenations using template literals.
'Hello ' + name + ', you have ' + count + ' messages.''₵' + (price * qty).toFixed(2) + ' total'\n way, then rewrite with a proper multi-line template literal\nA user has submitted messy form data. Clean it up.
const rawName = ' ama mensah '; const rawEmail = ' AMA@EXAMPLE.COM '; const rawPhone = ' +233 (0) 24-123-4567 ';
Practice finding and replacing content in strings.
censorWord(text, word) that replaces all occurrences of word with asterisks the same lengthhighlightQuery(text, query) that wraps every occurrence of query in <mark>...</mark>slugify(title) that converts a blog title to a URL slug: lowercase, spaces to hyphens, remove special charscensorWord('bad word here', 'bad') → '*** word here'highlightQuery('hello world', 'world') → 'hello <mark>world</mark>'slugify('Hello World! #1') → 'hello-world-1'Parse structured text data using split.
'Ama Mensah,22,Accra,student''Kwame Asante Boateng' → first: 'Kwame', last: 'Boateng', middle: 'Asante''14:35:22' into hours, minutes, seconds{ name: 'Ama Mensah', age: 22, city: 'Accra', role: 'student' }{ first: 'Kwame', middle: 'Asante', last: 'Boateng' }{ hours: 14, minutes: 35, seconds: 22 }Build a formatted receipt string from an order object.
const order = { id: 'ORD-2026-1042', items: [ { name: 'Kente Fabric', qty: 2, price: 85 }, { name: 'Woven Basket', qty: 1, price: 45 }, ], customer: 'Ama Mensah', };
padStart / padEnd so columns are neatWrite string utilities for displaying content in constrained spaces.
truncate(str, maxLength = 50) — cuts at maxLength and adds ...truncateWords(str, wordCount = 10) — cuts at a word boundary, not mid-wordexcerpt(str, query) — finds the query in the string and returns the surrounding context (50 chars before and after)truncate('Hello World', 8) → 'Hello...'truncateWords always cuts at a space — never mid-wordexcerpt highlights the query within its contextBuild number formatting utilities for a financial dashboard.
formatCurrency(amount, currency = 'GHS') → 'GHS 1,250.00'formatCompact(n) → 1.2K, 2.5M, 1.1BformatPercent(value, total) → '45.3%'addCommas(n) → '1,250,000' (manual implementation, no Intl)formatCurrency(1250) → 'GHS 1,250.00'formatCompact(1500) → '1.5K'formatPercent(3, 8) → '37.5%'addCommas(1000000) → '1,000,000'Build an SMS message system for a school notification platform.
buildSMS(template, data) — takes a template string with {placeholders} and an object, returns the filled messagebuildSMS('Hello {name}, your score is {score}.', { name: 'Ama', score: 78 }) → 'Hello Ama, your score is 78.''Hello <b>Ama</b>' → 'Hello Ama'Real applications communicate with servers. Practice async/await, fetching data, handling errors, and showing loading states — the skills used in every modern web application.
Fetch data from a public API and display it on the page.
https://jsonplaceholder.typicode.com/posts/1async/await inside an async functiontitle and body on the page in an <article> elementasync/await — not .then()Show a loading state while data is being fetched.
finally block to always hide the spinner, even on error/posts?_limit=10 and render them as a listHandle errors gracefully — network failures and HTTP error codes.
/posts/99999response.ok and throw a custom error if falseFetch multiple resources simultaneously using Promise.all.
await is slower than Promise.allconsole.time and console.timeEnd to compare both approachesPromise.allSend data to a server using a POST request.
https://jsonplaceholder.typicode.com/postsContent-Type: application/jsonJSON.stringifyid: 101 (JSONPlaceholder always returns this)Build a live search that fetches results as the user types — efficiently.
/usersLoad more posts automatically as the user scrolls to the bottom of the page.
IntersectionObserver on a sentinel element at the page bottomBuild a complete Create/Read/Update/Delete interface using the JSONPlaceholder API.
Writing code that works is the first step. Writing code that is readable, maintainable, and professional is the next. These exercises focus on habits that distinguish experienced developers from beginners.
Rewrite this bad code following all best practices from the chapter.
// BAD — rewrite this var x = 'Ama'; var y = 22; function d(a, b) { var z = a + b; if (z == 100) { return true; } else { return false; } }
var with const or let== with ===var in the rewritten codereturn total === targetRewrite deeply nested if/else using guard clauses to exit early.
// BAD — deeply nested function processOrder(order) { if (order) { if (order.paid) { if (order.items.length > 0) { return 'Processing'; } } } return 'Cannot process'; }
if blocks in the rewritten versionIdentify and eliminate the repeated logic in this code.
// BAD — repeated code const tax10 = (p) => p + (p * 0.10); const tax15 = (p) => p + (p * 0.15); const tax20 = (p) => p + (p * 0.20); const tax25 = (p) => p + (p * 0.25);
addTax(price, rate) functionconst makeTax = (rate) => (price) => price + (price * rate)addTax(100, 0.15) → 115Add proper error handling to code that currently crashes silently.
parseUserData(jsonString) — parse JSON safely. Return null if invalid, not a crashdivide(a, b) — throw a descriptive Error if b is 0getElement(id) — throw if the element does not exist in the DOMparseUserData('bad json') → null (no crash)divide(10, 0) throws Error: Cannot divide by zerogetElement('non-existent') throws Error: Element #non-existent not foundIdentify impure functions and rewrite them as pure functions.
// IMPURE — modifies external state let total = 0; function addToTotal(amount) { total += amount; } // IMPURE — mutates the input array function addItem(arr, item) { arr.push(item); return arr; }
addToTotal as a pure function: takes current total and amount, returns new totaladdItem as pure: returns a new array with the item — does not mutate the originaladdToTotal(100, 50) → 150, no external variable modifiedaddItem([1,2,3], 4) → [1,2,3,4], original array unchangedRewrite sequential async code as parallel and add proper error handling.
// BAD — sequential when parallel is possible async function loadDashboard() { const user = await fetchUser(); const posts = await fetchPosts(); const stats = await fetchStats(); }
Promise.all to fetch all three simultaneouslytry/catch with a meaningful error message in the UIconsole.time to prove the parallel version is fasterHarden these functions so they cannot crash regardless of what they receive.
getFirstName(user) — safely returns the first name even if user is null, undefined, or has no name property. Use optional chaining and nullish coalescing.sumArray(arr) — returns 0 if arr is not an array, filters out non-numbers before summingrenderList(items, container) — validates both arguments, handles empty arrays, no innerHTMLgetFirstName(null) → 'Unknown' (not a crash)sumArray('hello') → 0sumArray([1, 'x', 2, null, 3]) → 6renderList([], container) shows 'No items to display'Review and completely rewrite this function — it works, but it has serious problems.
var d = []; function p(i) { var x = document.getElementById(i); if (x != null) { var v = x.value; if (v != null && v != '') { d.push(v); return true; } else { return false; } } else { return false; } }
var, no single-letter names, no global variablesYou have completed all 96 exercises. Now build the full capstone project to prove your skills.
View Capstone Project →