Appearance
JavaScript Fundamentals
Turn static HTML and CSS pages into dynamic, interactive, data-driven web applications with modern ES6+ JavaScript.
14Weeks
5Stages
65+Lessons
9Projects
2Prerequisites
Download Official 2026 Curriculum PDF
Programme Overview
JavaScript is the programming language of the browser—and through Node.js, one of the most widely deployed server-side languages in the world. In Course 3 of the Tech Minds Web & Full-Stack Engineering sequence, you move beyond markup and styling into real algorithmic thinking, state updates, event-driven interfaces, asynchronous network communication, and modular software architecture.
| Attribute | Details |
|---|---|
| Course Position | Course 3 of 5 · Web & Full-Stack Engineering Track |
| Duration | 14 Weeks · 5 Progressive Stages · 65+ Mentor-Led Lessons |
| Prerequisites | HTML Mastery + CSS Mastery (or equivalent portfolio review) |
| Delivery Format | On-Campus (G5 Plaza, Sabon-Gari Road, Bwari, Abuja) & Live Interactive Online |
| Weekly Cadence | Live coding workshops, guided debugging labs, weekly GitHub submission, and 1-on-1 code review |
| Portfolio Output | 9 Weekly Interactive Mini-Apps + 1 Modular API-Powered ES6+ Capstone Web Application |
IMPORTANT
Before Week 1 begins, ensure Visual Studio Code, Node.js LTS, Git, and Google Chrome are installed by following the Developer Environment Setup and Git & GitHub Workflow guides.
Curriculum Rationale
Why JavaScript third?
Students who jump into JavaScript on Day 1 often struggle because they are simultaneously fighting syntax errors, HTML document structure, and CSS layout bugs. Having already completed HTML Mastery and CSS Mastery, you enter this programme fluent in semantic markup, Flexbox, and CSS Grid—allowing 100% of your cognitive energy to focus on logic, data structures, and runtime behaviour.
Why teach the DOM first (Week 3)?
Many traditional programming courses keep learners trapped in black-and-white console exercises for two months before touching a web page. At Tech Minds Academy, we introduce DOM Manipulation in Week 3 (document.querySelector, textContent, classList, and addEventListener). Seeing a button click immediately transform colours, counters, and cards on screen anchors abstract concepts like variables, conditionals, and functions in tangible visual feedback.
Why dedicate 3 full weeks to Async JavaScript & APIs?
Asynchronous execution—timers, Promises, async/await, network latency, HTTP status codes, and error recovery—is the single biggest stumbling block for self-taught developers. Dedicating Stage 4 (Weeks 9–11) exclusively to asynchronous flows ensures you understand why fetch() returns a Promise, how to coordinate concurrent requests with Promise.all(), how to debounce live search inputs, and how to handle loading, empty, and network-failure states gracefully.
What comes after this course?
Graduating from JavaScript Fundamentals unlocks the entire upper tier of Tech Minds engineering programmes:
- Frontend Engineering: Advance directly into React.js Mastery, where ES6 destructuring,
.map(),.filter(), closures, and ES Modules become your daily building blocks. - Backend Engineering: Enrol in Node.js & Backend Development (either sequentially or alongside React) to build Express REST APIs, PostgreSQL/MongoDB databases, and JWT authentication using the exact same language.
- AI Engineering: Transition into Agentic Software Engineering & MCP to build tool-calling LLM agents and Model Context Protocol servers in JavaScript/TypeScript.
Complete 14-Week Syllabus & Code Reference
Stage 1: JavaScript Foundations & Early DOM (Weeks 1–3)
Stage 1 introduces how browsers parse and execute scripts, how values live in memory, how expressions evaluate, and how JavaScript reads and mutates live HTML elements.
| Week | Core Topics & Lab Focus | Weekly Deliverable |
|---|---|---|
| Week 1 | How JS runs in Chrome V8; <script defer> placement; Chrome DevTools Console; let and const vs legacy var; primitive data types (string, number, boolean, null, undefined, bigint, symbol); typeof inspection; template literals `${expr}`. | Project 1: Interactive Console & Profile Greeting — Captures user details, formats strings cleanly with template literals, and logs structured diagnostics. |
| Week 2 | Arithmetic (+, -, *, /, %, **) and assignment operators; strict equality (===, !==) vs loose coercion (==); logical operators (&&, ||, !); ternary operator (condition ? a : b); Number(), parseInt(), toFixed(), and NaN guards. | Project 2: Precision Tip & Bill-Split Calculator — Computes Naira (₦) bill totals, service tips, and per-person splits with input validation. |
| Week 3 | The Document Object Model (DOM) tree; selecting nodes (querySelector, querySelectorAll); updating content (textContent vs innerHTML XSS risks); toggling styles via classList.add/remove/toggle; handling user events (addEventListener for 'click', 'input', 'submit'). | Project 3: Dynamic Theme & Colour Switcher — Interactive palette switcher with live hex/RGB readout, contrast state classes, and keyboard support. |
Annotated Reference: Strict Equality, Template Literals & Safe DOM Events
js
// Always prefer const by default; use let only when reassignment is required.
const billInput = document.querySelector('#bill-amount');
const tipSelect = document.querySelector('#tip-percent');
const splitInput = document.querySelector('#people-count');
const calculateBtn = document.querySelector('#calculate-btn');
const summaryEl = document.querySelector('#result-summary');
calculateBtn.addEventListener('click', () => {
const bill = Number(billInput.value);
const tipRate = Number(tipSelect.value);
const people = Number(splitInput.value);
// Strict comparison & NaN/boundary validation
if (Number.isNaN(bill) || bill <= 0 || people < 1) {
summaryEl.textContent = 'Please enter a valid bill amount and at least 1 person.';
summaryEl.classList.add('is-error');
return;
}
summaryEl.classList.remove('is-error');
const totalTip = bill * (tipRate / 100);
const grandTotal = bill + totalTip;
const perPerson = grandTotal / people;
// Safe textContent + template literal formatting (prevents HTML injection)
summaryEl.textContent = `Total: ₦${grandTotal.toFixed(2)} (₦${perPerson.toFixed(2)} each across ${people} ${people === 1 ? 'person' : 'people'})`;
});Stage 2: Control Flow & Functions (Weeks 4–6)
Stage 2 develops structured decision-making, iteration over sequences, modular reusable functions, lexical scope awareness, and higher-order callback patterns.
| Week | Core Topics & Lab Focus | Weekly Deliverable |
|---|---|---|
| Week 4 | Conditional branching (if, else if, else); the 6 classic falsy values (false, 0, "", null, undefined, NaN) vs truthy values; switch statements with break/return; logical short-circuiting (&&, ||) and guard clauses (early returns). | Project 4: 3-Question Interactive Quiz App — Tracks score, validates selections, prevents empty submissions, and displays graded feedback. |
| Week 5 | Classic for loops; while and do...while loops; for...of iteration over strings and collections; break vs continue; avoiding infinite loops; tracking state counters across user attempts. | Project 5: Number Guessing Game — Random target (Math.random), high/low hints, attempt counter, best-score tracking, and full game reset. |
| Week 6 | Function declarations vs expressions; parameters, arguments, and return values; concise arrow functions () => {}; global, function, and block scope ({}); closures intro; first-class functions & higher-order callbacks. | Project 6: Multi-Mode Unit Converter — Pure conversion functions (Celsius/Fahrenheit, km/miles, kg/lbs, NGN/USD) wired to live UI inputs via callbacks. |
Annotated Reference: Guard Clauses, Pure Functions & Higher-Order Callbacks
js
// Pure conversion helpers: predictable output, zero DOM side effects
const celsiusToFahrenheit = (c) => (c * 9) / 5 + 32;
const kmToMiles = (km) => km * 0.621371;
const kgToPounds = (kg) => kg * 2.20462;
// Registry mapping conversion modes to transformation callbacks
const converters = {
temp: { fn: celsiusToFahrenheit, fromUnit: '°C', toUnit: '°F' },
distance: { fn: kmToMiles, fromUnit: 'km', toUnit: 'mi' },
weight: { fn: kgToPounds, fromUnit: 'kg', toUnit: 'lb' }
};
// Higher-order formatter accepting a converter configuration
function formatConversion(rawValue, modeKey) {
const config = converters[modeKey];
// Guard clause: exit early on invalid mode or empty input
if (!config || rawValue === '' || Number.isNaN(Number(rawValue))) {
return 'Enter a numeric value to convert.';
}
const numericInput = Number(rawValue);
const converted = config.fn(numericInput);
return `${numericInput} ${config.fromUnit} = ${converted.toFixed(2)} ${config.toUnit}`;
}Stage 3: Arrays & Objects (Weeks 7–8)
Real-world applications rarely store data in dozens of disconnected variables. Stage 3 teaches you how to model lists and structured entities using arrays, objects, immutable transformation methods, and dynamic DOM rendering.
| Week | Core Topics & Lab Focus | Weekly Deliverable |
|---|---|---|
| Week 7 | Creating and indexing arrays; mutating methods (push, pop, shift, unshift, splice) vs non-mutating transformations (slice, forEach, map, filter, find, some, every, reduce); chaining array pipelines; array destructuring and spread ([...items]). | Project 7: Array-Powered To-Do List — Add, toggle complete, filter (All / Active / Completed), delete tasks, and compute live remaining counts with .filter(). |
| Week 8 | Object literals (key: value), dot vs bracket notation (obj[dynamicKey]), object methods and this basics; nested objects and arrays of objects; rendering structured data collections cleanly into DOM card grids; live search & category filtering. | Project 8: Filterable Product Listing Cards — Renders an e-commerce catalogue from an array of product objects with category filters, price sorting, and total inventory value via .reduce(). |
Annotated Reference: Array Pipelines (filter + map + reduce) & Dynamic Card Rendering
js
const products = [
{ id: 'p1', name: 'Mechanical Keyboard', category: 'Accessories', priceNgn: 68000, inStock: true },
{ id: 'p2', name: '27" IPS Monitor', category: 'Displays', priceNgn: 245000, inStock: true },
{ id: 'p3', name: 'USB-C Hub (8-in-1)', category: 'Accessories', priceNgn: 32000, inStock: false },
{ id: 'p4', name: 'Ergonomic Laptop Stand', category: 'Accessories', priceNgn: 27500, inStock: true }
];
function renderCatalogue(items, selectedCategory = 'ALL', onlyAvailable = false) {
const gridEl = document.querySelector('#product-grid');
const totalValueEl = document.querySelector('#inventory-total');
// 1. Filter without mutating the original products array
const visibleItems = items.filter((product) => {
const matchesCategory = selectedCategory === 'ALL' || product.category === selectedCategory;
const matchesStock = !onlyAvailable || product.inStock;
return matchesCategory && matchesStock;
});
// 2. Compute aggregate total using .reduce()
const totalNgn = visibleItems.reduce((sum, item) => sum + item.priceNgn, 0);
totalValueEl.textContent = `Showing ${visibleItems.length} items · Total: ₦${totalNgn.toLocaleString('en-NG')}`;
// 3. Build DOM nodes safely and replace children in one batch
const fragment = document.createDocumentFragment();
visibleItems.forEach(({ name, category, priceNgn, inStock }) => {
const card = document.createElement('article');
card.className = 'product-card';
const title = document.createElement('h3');
title.textContent = name;
const meta = document.createElement('p');
meta.textContent = `${category} · ₦${priceNgn.toLocaleString('en-NG')} · ${inStock ? 'In Stock' : 'Out of Stock'}`;
card.append(title, meta);
fragment.appendChild(card);
});
gridEl.replaceChildren(fragment);
}Stage 4: Asynchronous JavaScript & Web APIs (Weeks 9–11)
Stage 4 demystifies the JavaScript Event Loop, timers, Promises, async/await, RESTful fetch() requests, UI state machines (idle, loading, error, success), input debouncing, and client-side caching with localStorage.
| Week | Core Topics & Lab Focus | Weekly Deliverable |
|---|---|---|
| Week 9 | Synchronous single-threaded execution vs the Event Loop & Task Queue; setTimeout and setInterval (and clearing intervals with clearInterval); callback-hell pitfalls; Promises (pending, fulfilled, rejected), .then(), .catch(), .finally(), and parallel execution with Promise.all(). | Project 9a (Stage Lab): Event Countdown & Pomodoro Timer — Accurate interval timer with pause, resume, reset, and completion alert state. |
| Week 10 | Modern async and await syntax; structured error handling with try / catch / finally; HTTP fundamentals (methods GET & POST, headers, status codes 200, 201, 400, 404, 500, JSON serialization); checking response.ok explicitly with fetch(). | Project 9b: Live City Weather App — Fetches real-time meteorological JSON for Abuja, Lagos, London, or any searched city with loading skeletons and friendly network error banners. |
| Week 11 | URL query parameters with URLSearchParams; debouncing rapid keystrokes so APIs aren't spammed; cancelling stale requests with AbortController; persisting user favourites and recent caches in localStorage (JSON.stringify / JSON.parse). | Project 9: Movie Search & Watchlist App (OMDB API) — Debounced live search, detail modal fetch, error/empty states, and persistent localStorage watchlist. |
Annotated Reference: Production-Grade async/await Fetch with Debounce & localStorage Cache
js
const CACHE_PREFIX = 'tm_weather_v1:';
const CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes
// Reusable debounce utility: delays execution until user pauses typing
function debounce(fn, delayMs = 400) {
let timerId;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(() => fn(...args), delayMs);
};
}
async function fetchCityWeather(cityName) {
const normalizedKey = `${CACHE_PREFIX}${cityName.trim().toLowerCase()}`;
// 1. Check fresh localStorage cache first
const cachedRaw = localStorage.getItem(normalizedKey);
if (cachedRaw) {
const cached = JSON.parse(cachedRaw);
if (Date.now() - cached.savedAt < CACHE_TTL_MS) {
return { data: cached.payload, fromCache: true };
}
}
// 2. Build safe query string using URLSearchParams
const params = new URLSearchParams({
name: cityName.trim(),
count: '1',
language: 'en',
format: 'json'
});
const geoRes = await fetch(`https://geocoding-api.open-meteo.com/v1/search?${params}`);
// Always check response.ok — fetch() only rejects on network failure, not HTTP 404/500!
if (!geoRes.ok) {
throw new Error(`Geocoding service failed (HTTP ${geoRes.status})`);
}
const geoJson = await geoRes.json();
if (!geoJson.results || geoJson.results.length === 0) {
throw new Error(`No city found matching "${cityName}".`);
}
const { name, country, latitude, longitude } = geoJson.results[0];
const weatherParams = new URLSearchParams({
latitude: String(latitude),
longitude: String(longitude),
current: 'temperature_2m,relative_humidity_2m,wind_speed_10m'
});
const weatherRes = await fetch(`https://api.open-meteo.com/v1/forecast?${weatherParams}`);
if (!weatherRes.ok) {
throw new Error(`Weather forecast failed (HTTP ${weatherRes.status})`);
}
const weatherJson = await weatherRes.json();
const payload = {
location: `${name}, ${country}`,
tempC: weatherJson.current.temperature_2m,
humidity: weatherJson.current.relative_humidity_2m,
windKmh: weatherJson.current.wind_speed_10m
};
// 3. Persist fresh response in localStorage
localStorage.setItem(normalizedKey, JSON.stringify({ savedAt: Date.now(), payload }));
return { data: payload, fromCache: false };
}
// UI Controller handling Loading, Success, and Error states
async function handleCitySearch(query) {
const statusEl = document.querySelector('#weather-status');
const cardEl = document.querySelector('#weather-card');
if (query.trim().length < 2) return;
statusEl.textContent = 'Fetching live weather...';
cardEl.hidden = true;
try {
const { data, fromCache } = await fetchCityWeather(query);
statusEl.textContent = fromCache ? 'Loaded from local cache' : 'Updated live';
cardEl.textContent = `${data.location}: ${data.tempC}°C · Humidity ${data.humidity}% · Wind ${data.windKmh} km/h`;
cardEl.hidden = false;
} catch (error) {
statusEl.textContent = error.message || 'Unable to load weather right now.';
}
}
const searchInput = document.querySelector('#city-input');
searchInput.addEventListener('input', debounce((e) => handleCitySearch(e.target.value), 450));Stage 5: Modern ES6+, Modules, Vite & Capstone (Weeks 12–14)
Stage 5 prepares you for modern engineering teams and frameworks like React and Node.js. You will refactor monolithic script files into clean ES Modules, adopt defensive ES2020+ operators, initialise a Vite build workflow with npm, and ship your Capstone application.
| Week | Core Topics & Lab Focus | Weekly Deliverable |
|---|---|---|
| Week 12 | Deep ES6+ ergonomics: nested object/array destructuring with aliases, rest parameters (...args), spread cloning, default parameters, optional chaining (?.), nullish coalescing (?? vs ||), Array.prototype.flat(), flatMap(), Object.keys(), Object.values(), and Object.entries(). | Stage 5 Refactoring Lab — Upgrade legacy callback/script codebases to concise, defensive ES2022+ syntax. |
| Week 13 | Multi-file architecture with native ES Modules (export, export default, import, <script type="module">); separating concerns across api.js, render.js, storage.js, and main.js; intro to npm, package.json, .gitignore, and Vite dev server & production bundling (npm create vite@latest). | Modular Architecture Blueprint — Scaffolded Vite vanilla-JS repository with clean module boundaries and GitHub deployment workflow. |
| Week 14 | Capstone architecture sprint, state/edge-case QA, responsive polish, Lighthouse check, README documentation, live deployment (Netlify / Vercel / GitHub Pages), and live cohort code defence. | Final Capstone Web Application (choose 1 of 3 tracks below). |
Annotated Reference: Clean Multi-File ES Module Architecture (api.js + render.js + main.js)
js
// 1. src/api.js — Isolated network & data normalization layer
const GITHUB_API = 'https://api.github.com/users';
export async function getDeveloperProfile(username = 'octocat') {
const cleanHandle = username.trim();
const [userRes, reposRes] = await Promise.all([
fetch(`${GITHUB_API}/${encodeURIComponent(cleanHandle)}`),
fetch(`${GITHUB_API}/${encodeURIComponent(cleanHandle)}/repos?sort=updated&per_page=5`)
]);
if (!userRes.ok) {
throw new Error(userRes.status === 404 ? 'GitHub user not found.' : 'GitHub API rate limit or error.');
}
const user = await userRes.json();
const repos = reposRes.ok ? await reposRes.json() : [];
// Optional chaining (?.) and nullish coalescing (??) provide safe defaults
return {
handle: user?.login ?? cleanHandle,
displayName: user?.name ?? user?.login ?? 'Anonymous Developer',
bio: user?.bio ?? 'No public bio provided.',
followers: user?.followers ?? 0,
location: user?.location ?? 'Remote',
topRepos: repos.map((repo) => ({
name: repo.name,
stars: repo.stargazers_count ?? 0,
language: repo.language ?? 'Text',
url: repo.html_url
}))
};
}js
// 2. src/render.js — Pure DOM presentation layer
export function renderProfileCard(container, profile) {
const repoItems = profile.topRepos
.map((r) => `${r.name} (${r.language} · ★ ${r.stars})`)
.join(' | ');
container.textContent = '';
const heading = document.createElement('h2');
heading.textContent = `${profile.displayName} (@${profile.handle})`;
const details = document.createElement('p');
details.textContent = `${profile.bio} — ${profile.location} · ${profile.followers} followers`;
const reposLine = document.createElement('p');
reposLine.textContent = repoItems || 'No public repositories yet.';
container.append(heading, details, reposLine);
}js
// 3. src/main.js — Application entry point wiring events, API, and UI
import { getDeveloperProfile } from './api.js';
import { renderProfileCard } from './render.js';
const form = document.querySelector('#search-form');
const input = document.querySelector('#username-input');
const output = document.querySelector('#profile-container');
form.addEventListener('submit', async (event) => {
event.preventDefault();
output.textContent = 'Loading profile...';
try {
const profile = await getDeveloperProfile(input.value);
renderProfileCard(output, profile);
} catch (err) {
output.textContent = err.message;
}
});Week 14 Capstone Project Options
Every student builds, documents, deploys, and defends one complete, modular Vite + ES6+ web application from scratch:
- Recipe Finder & Meal Planner App — Live search against a public recipe REST API, ingredient/category filters, nutrition/prep detail view, debounced search input, error/empty states, and a persistent
localStorageweekly meal-plan drawer. - GitHub Developer Profile & Repo Explorer — Concurrent
Promise.all()requests fetching user metadata and repositories, language filter chips, star/update sorting, rate-limit handling, recent-search caching, and light/dark theme persistence. - Live Crypto Market Tracker — Fetches live market data (price, 24h change, market cap), supports NGN/USD currency toggling, search + top-gainers/losers filtering, watchlist pinning in
localStorage, and manual/timed refresh controls.
Assessment & Grading Rubric
Consistent with the Tech Minds Academy engineering standard, grades are earned through working code and live technical comprehension rather than rote memorisation exams:
| Assessment Component | Weight | Evaluation Criteria |
|---|---|---|
| Weekly Projects (x9) | 40% | Submitted weekly via GitHub: clean let/const usage, zero uncaught console errors, defensive input validation, and accessible DOM updates. |
| Stage Assessments (x5) | 30% | Timed practical coding & debugging checkpoints at Weeks 3, 6, 8, 11, and 13 testing control flow, array transformations, and async/await error handling. |
| Capstone Web Application | 30% | Multi-module ES6+ Vite architecture (api.js, render.js, main.js), live API integration, loading/error/empty states, localStorage persistence, responsive UI, and live code defence. |
TIP
A minimum cumulative score of 70% and a deployed Capstone project with a documented README.md are required to earn the verified Tech Minds JavaScript Fundamentals Certificate and unlock React.js or Node.js cohort admission.
Learning Outcomes
By the end of Week 14, you will confidently be able to:
- Write clean, predictable ES6+ JavaScript using
const/let, strict equality (===), template literals, destructuring, optional chaining (?.), and nullish coalescing (??). - Select, traverse, create, and update DOM elements safely while wiring responsive event listeners without XSS vulnerabilities.
- Transform, filter, sort, and aggregate complex arrays of objects using immutable
.map(),.filter(),.find(), and.reduce()pipelines. - Orchestrate asynchronous workflows using Promises,
Promise.all(),async/await,try/catch, input debouncing, andlocalStoragecaching against live REST APIs. - Structure maintainable multi-file frontend codebases using native ES Modules (
import/export),npm, and Vite, and deploy live builds to production hosting.
Tools & Learning Resources
| Tool / Platform | Role in This Course |
|---|---|
| Visual Studio Code | Primary code editor with ESLint, Prettier, and Live Server / Vite terminal integration |
| Chrome DevTools | Console inspection, Sources breakpoint debugger, Network tab (fetch payload/status inspection), and Application (localStorage) viewer |
| Node.js (LTS) & npm | Local JavaScript runtime and package manager used in Stage 5 for Vite scaffolding |
| Vite | Lightning-fast ES Module development server and production bundler (npm run dev / npm run build) |
| Git & GitHub | Version control for all 9 weekly projects, pull-request reviews, and Capstone hosting |
| MDN Web Docs & javascript.info | Canonical language specification references used alongside Tech Minds lab notes |
| Netlify / Vercel / GitHub Pages | Production static hosting platforms for live project URLs |
Next Steps in Your Track
- Continue Frontend: 4. React.js Mastery (14 Weeks) — Component architecture, Hooks, React Router, Zustand, React Hook Form, and Vitest testing.
- Continue Backend: 5. Node.js & Backend Development (15 Weeks) — Express.js REST APIs, MongoDB & PostgreSQL/Prisma, JWT auth, security hardening, and automated API testing.
- Need to review prerequisites? Revisit 1. HTML Mastery or 2. CSS Mastery.
