Web development module 3: JavaScript, the page that reacts
Fourteen sessions to bring your pages alive: the basics of the JavaScript language (variables, conditions, functions), then the DOM — the gate between JavaScript and the page — and events, up to three useful widgets: a counter, a todo list and a dark-mode toggle, plus a call to a public API. Everything happens in the browser, with nothing to install.
Day 29 — JavaScript in the page, the console
Goal: plug a script into a page, print a first message, and use the console.
Theory (20 min)
JavaScript is the language that runs inside the browser and gives the page behavior: reacting to clicks, changing content without reloading, fetching data. No relation to Java despite the name — a 1995 marketing move.
Like CSS, JavaScript lives in its own file, linked by a <script> tag placed just before </body>:
<script src="script.js"></script>
At the end of the body, not in the head: the script runs as soon as it is read, and it needs the HTML to already exist to manipulate it. (A defer attribute exists to put it in the head — module 4 will use it.)
First function: console.log(...) prints whatever you give it in the developer tools console (F12, Console tab) — invisible on the page, it is your logbook:
console.log("Hello from JavaScript");
console.log(2 + 2);
The console is also a playground: you can type JavaScript directly into it, line by line, and see the result immediately. It is the browser's REPL.
Practice (30 min)
- In your folder, create
module3, copy yourme.htmlpage into it, and create an emptyscript.jsnext to it. Add the<script>tag before</body>. - In
script.js, type the two lines above. Save, reload, open the console (F12). Success criterion: "Hello from JavaScript" and "4" appear in the console. - Provoke an error: write
console.log("test"without the closing parenthesis, reload. The console shows a red error with a line number: it is the voice that will talk to you whenever something breaks. Read it, fix it. - Change the
srcpath to a wrong name: the console shows a 404 on script.js — same diagnosis as day 15 for CSS. Repair it. - Type directly in the console:
2 + 2, then"hello".toUpperCase(). You are running JavaScript live.
Agent tips: "here is the red error from my console: [paste], and here is the line it points at: [paste]" — the diagnosis is almost always immediate. Trap: without the exact error text, it guesses. Proof: fix the line it names yourself, and check the console is clean again.
Recap (10 min)
Three lines: where the script tag lives and why, what the console is, what console.log does. Then plug a script from memory onto a fresh page.
Day 30 — Variables and types
Goal: store values with let and const, and tell the three basic types apart.
Theory (20 min)
A variable is a name pointing at a value — the labelled box. In modern JavaScript, you declare it with const (the value will not be reassigned — the default choice) or let (it may change):
const firstName = "Alice";
let score = 0;
score = score + 10;
The old var keyword lingers in old tutorials: do not use it; const and let have replaced it since 2015. Reassigning a const variable raises an error — on purpose: the machine tells you that you contradict yourself.
Three value types do most of the work: strings (text, in quotes: "hello"), numbers (42, 3.14 — JavaScript has a single number type) and booleans (true or false). The typeof operator tells a value's type: typeof "hello" answers "string".
Beware the beginner's trap: "5" + 3 gives "53" — a string plus a number glues characters instead of adding. "5" with quotes is text that looks like a number, not a number.
What is "5" + 3 in JavaScript?
- 8
- An error
- "53"
Answer
"53": + with a string concatenates instead of adding.
Practice (30 min)
- In
script.js, declareconst firstName,let year,const isMember = true;, and print the three withconsole.log. Reload, read the console. - Try reassigning the const:
firstName = "Bob";— reload, read the error, delete the line. You now know what "Assignment to constant variable" means. - Test the trap:
console.log("5" + 3)thenconsole.log(Number("5") + 3). TheNumber()function converts text to a number. Success criterion: the console shows 53 then 8, and you can explain the difference. - Check the types:
console.log(typeof firstName),typeof year,typeof isMember. - In the notebook: when const, when let? (Answer: const by default, let when the value must change.)
Agent tips: "why does this computation give 53 instead of 8?" — paste the line. Trap: it may drown the answer (coercion, specification); ask "in one sentence". Proof: the fix must go through Number() and you test it in the console.
Recap (10 min)
Three lines: const vs let, the three types, the "5" + 3 trap. Then rewrite the mini-program from memory.
Day 31 — Strings, numbers, template literals
Goal: assemble text with template literals and make JavaScript compute.
Theory (20 min)
Concatenating text with + quickly turns unreadable. Template literals fix that: the string is written between backticks `, and values are interpolated in ${...}:
const firstName = "Alice";
const age = 32;
console.log(`My name is ${firstName} and I am ${age} years old.`);
Inside ${}, any expression goes: ${age + 1} prints 33.
On the numbers side: + - * / do the four operations, % gives the division remainder (10 % 3 is 1 — n % 2 === 0 tests whether n is even), and parentheses set the order. The Math object provides the common tools: Math.round(3.6) rounds (4), Math.floor(3.6) rounds down (3), Math.random() gives a number between 0 and 1.
A string is also an object full of tools: text.length (character count), text.toUpperCase(), text.includes("word") (true if the word is in it), text.trim() (strips edge spaces — indispensable on user input).
`Total: ${10 + 5}` prints…
- Total: ${10 + 5}
- Total: 15
- An error
Answer
Total: 15 — the expression inside ${} is evaluated.
Practice (30 min)
- Write the template literal above with your values, reload, read the console.
- Build a sentence mixing text and computation: "Next year I will be X", with the addition done inside the
${}. Success criterion: the printed age is computed by the code, not written by you. - Test
" hello ".trim()in the console: the edge spaces vanish. - Write an evenness test:
const n = 7; console.log(n % 2 === 0);prints false. Change n to 8: true. - Play with
Math.random(): printMath.floor(Math.random() * 6) + 1several times — you have just written a six-sided die.
Agent tips: "turn these concatenations into template literals" is a perfect refactor. Trap: it may change the printed text along the way. Proof: compare the console output before/after, identical character by character.
Recap (10 min)
Three lines: template literal syntax, the operators, three Math or string tools. Then rewrite the six-sided die from memory.
Day 32 — Conditions
Goal: let the program decide with if / else if / else and the comparison operators.
Theory (20 min)
A condition runs a block only if a test is true:
const age = 17;
if (age >= 18) {
console.log("adult");
} else if (age >= 13) {
console.log("teenager");
} else {
console.log("child");
}
The test in parentheses is a boolean. The comparison operators: === (equal, ALWAYS use this one — the historical == silently converts types and holds surprises: "5" == 5 is true!), !== (different), < <= > >=. Logical operators combine: && (AND: both true), || (OR: at least one true), ! (NOT: inverts).
JavaScript classifies every value as "truthy" or "falsy" when placed in a test: falsy are false, 0, "" (empty string), null, undefined, NaN; everything else is truthy. So if (text) means "if text is not empty".
Why prefer === over ==?
- === compares without converting types: "5" === 5 is false, no surprise
- === is faster
- == no longer exists in modern JavaScript
Answer
=== is strict: no hidden conversion. == converts, and "5" == 5 becomes true.
Practice (30 min)
- Type the age program, test with 17, 25, 9: three different answers in the console.
- Write an input check:
const password = "cat";then an if that prints "too short" ifpassword.length < 8, "accepted" otherwise. Test with "cat" then "savanna-giraffe". Success criterion: both branches print depending on length. - Combine: access granted if
age >= 18 && isMember. Test the four combinations of your two variables. - Test falsy:
const input = ""; if (input) { console.log("full"); } else { console.log("empty"); }— prints "empty". Put a single space in the string: "full"! A space is a character. (You now understand why wetrim()before testing.)
Agent tips: "review these conditions and list the cases I have not tested" is an excellent safety net. Trap: it may "run it in its head" and miss the one-space-string case. Proof: test each case it cites, in the console, yourself.
Recap (10 min)
Three lines: the if/else if/else shape, === vs ==, what falsy means. Then rewrite the length check from memory.
Day 33 — Functions
Goal: write functions with parameters and return values, and reuse them.
Theory (20 min)
A function is a named block of code you can call as many times as you like. Define it once, call it everywhere:
function greet(name) {
return `Hello ${name}!`;
}
console.log(greet("Alice"));
console.log(greet("Bob"));
The parts: name is a parameter — the input variable, which exists only inside the function. return hands the result back to the caller and stops the function: anything written after it never runs. A function without return returns undefined.
A key distinction: console.log PRINTS, return HANDS BACK. Printing does not let you reuse the value; returning does. A function that returns can feed a computation, a test, a text: const message = greet("Alice");.
You will meet the "arrow" notation: const greet = (name) => `Hello ${name}!`; — a short function stored in a constant. Equivalent for this path; just learn to read it.
What does a function without return give back?
- null
- undefined
- An error
Answer
undefined: without return, the function gives back nothing, and "nothing" is written undefined.
Practice (30 min)
- Type
greet, call it with three first names. - Write
function area(width, height)returning the product, and printarea(3, 4). Success criterion: the console shows 12, computed by the function. - Write
function isEven(n)returning a boolean (return n % 2 === 0;), then use it INSIDE a condition:if (isEven(7)) { ... }. A function returning a boolean is a reusable test. - Write
function priceWithTax(netPrice, rate)returningnetPrice * (1 + rate), and print a template: "Price with tax: X €" (or your currency). - Deliberate trap: replace the return with a console.log in
area, then printarea(3, 4) * 2: the console shows NaN (Not a Number — undefined cannot be multiplied). Repair. You have seen the print/return difference for real.
Agent tips: "write a function priceWithTax(netPrice, rate)" is a good order, small and checkable. Trap: it may print instead of returning. Proof to demand: console.log(priceWithTax(100, 0.2)) must print 120 — test it.
Recap (10 min)
Three lines: parameter vs argument, return vs console.log, why a boolean function is handy. Then rewrite isEven from memory.
Day 34 — The DOM: reading the page
Goal: select a page element from JavaScript, read and change its text.
Theory (20 min)
When the browser reads your HTML, it builds an in-memory representation: the DOM (Document Object Model) — the tree of elements, as the inspector shows it. JavaScript sees the page THROUGH the DOM: changing the DOM changes the displayed page, without touching the file.
Selecting an element uses the CSS selectors you know:
const heading = document.querySelector("h1"); // the first h1
const callout = document.querySelector(".callout"); // the first of the class
const field = document.querySelector("#firstname"); // by id
const links = document.querySelectorAll("a"); // ALL the links (a list)
document is the object representing the whole page. querySelector returns the first matching element, or null if none matches — the number one cause of the "Cannot read properties of null" error: the selector matches nothing (typo, or script loaded before the HTML — remember day 29).
Once the element is in hand, you read and change it:
console.log(heading.textContent); // read its text
heading.textContent = "New heading"; // replace its text
callout.classList.add("visible"); // add a CSS class
callout.classList.remove("callout");
Prefer textContent (plain text, period) over innerHTML (which interprets HTML — useful but dangerous with content coming from the user: it is the gate to XSS attacks, module 4 comes back to it).
Practice (30 min)
- In
script.js, select your page's h1 and print its text in the console. - Change it:
heading.textContent = "Welcome";, reload. Success criterion: the displayed heading is "Welcome" while your HTML file has not changed — check the source (right-click → view source): still the old one. The DOM changed, not the file. - Provoke the null: select
".missing"and read its textContent: red error. Read it, it says everything. Print the variable:null. Fix the selector. - Test
querySelectorAll("p")and print the list's.length: the number of paragraphs on your page. - Add a class to an element from the script, and give that class a visible style in your CSS. The style changes without reloading: the mechanism behind the other day's dark mode.
Agent tips: "Cannot read properties of null, here is my selector and my HTML" — the diagnosis is immediate. Trap: it may answer "add defer" without checking the selector typo. Proof: first print the selected variable in the console — null or element, the console decides.
Recap (10 min)
Three lines: what the DOM is, querySelector vs querySelectorAll, why textContent over innerHTML. Then change a text from memory.
Day 35 — Events: the counter
Goal: react to clicks with addEventListener and build a counter.
Theory (20 min)
The page emits events all the time: click, keystroke, form submission, scrolling… JavaScript can listen for an event on an element and run a function when it happens:
const button = document.querySelector("#plus");
button.addEventListener("click", function () {
console.log("clicked!");
});
The parts: the element listened to, the event name ("click"), and the function to run — called a listener. It does not run now: it will run on every click. This is the reversal from the previous module: your code no longer runs top to bottom once; it waits and reacts.
Everything assembles into the path's first widget, the counter:
let count = 0;
const button = document.querySelector("#plus");
const display = document.querySelector("#count");
button.addEventListener("click", function () {
count = count + 1;
display.textContent = count;
});
The matching HTML: <button id="plus">+1</button> <p>Count: <span id="count">0</span></p>. Notice the cycle: state lives in a JavaScript variable, and the display is only its reflection, updated on every change.
Practice (30 min)
- Add the button and paragraph above to your page, then the counter script. Reload, click. Success criterion: each click increments the displayed number, without reloading the page (watch the tab: no reload).
- Add a "-1" button with its own listener.
- Add a "Reset" button.
- Challenge: the counter must not go below zero — a condition in the "-1" listener.
- Style the buttons with your CSS (class, hover): a widget is HTML + CSS + JS, the three languages together.
Agent tips: "write a +1/-1/reset counter in vanilla JS" produces this code at once. Trap: it may select buttons by their text or forget the HTML does not exist yet. Proof: click each button three times, including -1 at zero — the behavior must be exactly the planned one.
Recap (10 min)
Three lines: the three parts of addEventListener, why state lives in a variable, what a listener is. Then redo the counter from memory.
Day 36 — Arrays and loops
Goal: store collections in an array and walk through them with a loop.
Theory (20 min)
An array is an ordered list of values, written between square brackets:
const groceries = ["apples", "bread", "rice"];
console.log(groceries[0]); // "apples" — counting starts at ZERO
console.log(groceries.length); // 3
groceries.push("coffee"); // appends at the end
groceries[1] = "whole bread"; // changes slot 1
The index starts at zero: the first element is [0], and the last is [length - 1]. Asking for a slot beyond the end gives undefined, not an error — a source of silent bugs.
To walk through, the for...of loop:
for (const item of groceries) {
console.log(item);
}
"for each item of the groceries array, do…". It visits every element, in order, once. (The classic for (let i = 0; i < groceries.length; i++) loop still exists; for...of covers most cases and reads better.)
Arrays also have transforming methods: groceries.map(...) builds a new array by transforming each element, groceries.filter(...) keeps those passing a test. Note they exist; for...of covers your needs this month.
With const t = ["a", "b", "c"];, what is t[1]?
- "a"
- undefined
- "b"
Answer
"b": the index starts at zero, so [1] is the second element.
Practice (30 min)
- Create an array of five first names, print the first, the last (with
length - 1), and the size. - Walk it with
for...ofand print "Hello X" for each. - Array of numbers: compute the sum with a loop (a
let total = 0;variable before the loop,total = total + n;inside). Success criterion: print the sum AND the average, computed by the code. - Filter by hand: a loop that only prints names longer than five letters (
n.length > 5). - Ask for
groceries[99]: undefined, silently. Note it in the notebook: a missing slot does not shout.
Agent tips: "why does my loop print undefined on the last line?" — paste the loop. Classic trap: i <= length instead of <. Proof: the fix is ONE inequality; refuse the full rewrite.
Recap (10 min)
Three lines: the index starting at zero, for...of, push. Then redo the average computation from memory.
Day 37 — Creating elements in the page
Goal: generate HTML from JavaScript: create elements and add them to the page.
Theory (20 min)
Yesterday you walked an array into the console. Today, each walked element becomes a page element. Three methods are enough:
const list = document.querySelector("#groceries");
for (const item of ["apples", "bread", "rice"]) {
const li = document.createElement("li"); // creates the element (in memory)
li.textContent = item; // fills its text
list.appendChild(li); // hooks it to the page
}
The trio create → fill → hook is THE DOM gesture. A created element exists only in memory until appendChild attaches it to a page element.
You can also remove: li.remove() deletes the element from the page.
Compare with the alternative list.innerHTML = "<li>" + item + "</li>";: shorter, but the string is interpreted as HTML — if item comes from user input and contains <script>, the script runs. That is the XSS hole. Rule of the path: content coming from outside (input, API) goes through textContent and createElement, never through innerHTML.
Practice (30 min)
- In your page, add an empty
<ul id="groceries"></ul>, and the script above. Reload: the list appears, built by JavaScript. Success criterion: the inspector shows the three<li>while your HTML file has an empty<ul>. - Replace the hardcoded array with yesterday's first-names array: the page displays the list.
- Add to each
lia "×" button (created withcreateElement, hooked to the li) whose listener runsli.remove(): every row becomes deletable. - Test the XSS trap, knowingly, in a throwaway file: inject
"<img src=x onerror=alert(1)>"via innerHTML, then via textContent. The first executes, the second prints the text as-is. You will not use innerHTML on user input again.
Agent tips: "generate a ul list from this array in JS" is a classic order. Trap: the returned solution often uses innerHTML. Proof to demand: createElement + textContent, and test with a value containing angle brackets.
Recap (10 min)
Three lines: the create/fill/hook trio, what remove does, why not innerHTML on input. Then regenerate a list from memory.
Day 38 — Reading a form in JavaScript
Goal: intercept a form submission, read the input, and use it in the page.
Theory (20 min)
On day 9, submitting the form reloaded the page. JavaScript can intercept that submission:
const form = document.querySelector("#my-form");
form.addEventListener("submit", function (event) {
event.preventDefault(); // stops the reload
const field = document.querySelector("#firstname");
const input = field.value.trim(); // .value reads a field's content
if (input === "") {
return; // bail out, do nothing
}
console.log(`Typed: ${input}`);
field.value = ""; // empties the field for next time
});
Three notions: event is the object the browser hands the listener to describe what happened; preventDefault() announces "do not do the default behavior" (the reload); .value reads (and writes) a field's content — a property of form fields, not textContent.
Validating on the page (length, empty field) improves comfort — the answer is immediate. But remember: this validation can be bypassed by anyone (dev tools can change anything). The validation that truly protects happens on the server — you have none yet; module 4 will publish static pages.
Practice (30 min)
- Give an
idto your contact form and to the first-name field, and hook the listener above. Reload, type, submit. Success criterion: the page does NOT reload (the URL stays clean), the console prints the input, and the field empties. - Replace the console.log with a real display: a
<p id="confirmation">in the page, whose textContent you fill: "Thank you, X!". - Empty field: submit with nothing typed — nothing happens (the return). Add a "First name is required" message shown in that case.
- Test the Enter key inside the field: it submits the form, like clicking the button. Native behavior, free, and keyboard users count on it.
Agent tips: "intercept this submit and show the input in a p" delegates well. Trap: it may forget preventDefault, and the page reloads — you will think the JS is broken. Proof: submit the form; the URL must NOT gain a ?....
Recap (10 min)
Three lines: preventDefault, .value vs textContent, why page-side validation does not protect. Then redo the interception from memory.
Day 39 — The complete todo list
Goal: assemble form, array and DOM into the classic widget: the todo list.
Theory (20 min)
The todo list is THE second widget of the path: it combines the whole module. The architecture, worth remembering because it applies everywhere:
- State: a JavaScript array holds the tasks — the source of truth;
- Display: a
render()function empties the HTML list and rebuilds it from the array; - Actions: the listeners (submit, click) change the array, then call
render().
const todos = [];
function render() {
list.innerHTML = ""; // clears the display (on your own elements: safe)
for (const t of todos) {
const li = document.createElement("li");
li.textContent = t;
list.appendChild(li);
}
}
When "add" is clicked: todos.push(input) then render(). The "change the data, then re-render" reflex is the heart of every interface, from the widget to React.
To delete a task, each row needs to know which one it carries: store the index in the button, or filter the array: todos.splice(index, 1) removes one element at the given position.
Practice (30 min)
- Build the
todos.htmlpage: a form (field + "Add" button), an empty<ul id="list">, the script with the array,render(), and the submit listener. - Success criterion: add three tasks — they display, without reload, and the field empties between each.
- Add to each row a "×" button that removes the task from the array (splice) then re-renders. Test: delete the middle task and check the others keep their order.
- Reject empty or all-spaces tasks (trim + the day-32 empty test).
- Bonus if time remains: clicking a task's text strikes it through (add/remove a CSS class
.done { text-decoration: line-through; }).
Agent tips: "write a vanilla JS todo list with add and delete" is the RORSCHACH test of delegation: the code will look plausible. Trap: test deleting the MIDDLE element; that is where indexes go wrong. Proof: three adds, one middle deletion, one empty-input rejection.
Recap (10 min)
Three lines: the state/render/actions architecture, what splice does, why re-render from state. Keep this page: day 41 will give it a memory.
Day 40 — fetch: calling a public API
Goal: fetch data from a public service with fetch and display it.
Theory (20 min)
An API (Application Programming Interface) is a service's front door made for programs rather than humans: instead of an HTML page, it returns raw data, most often in JSON (JavaScript Object Notation) — text structured in "key": value pairs, easy for machines to read and readable for us.
JavaScript calls an API with fetch:
fetch("https://wttr.in/Paris?format=j1")
.then(function (response) { return response.json(); })
.then(function (data) {
console.log(data.current_condition[0].temp_C);
});
fetch sends the HTTP request; the response arrives later, when the network answers — that is asynchronous: the code does not stop and wait, and .then() chains what to do when the response lands. The first .then turns the received text into JavaScript data (.json()), the second uses it.
wttr.in is a free weather service, no account, no key, designed for the terminal, whose ?format=j1 format returns full JSON (temperature, wind, forecast) — perfect for practice. If it ever fails to answer, JSONPlaceholder offers fake data (users, posts) with the same mechanics.
And when the network fails? A .catch() at the end of the chain catches the error — otherwise it stays silent.
Practice (30 min)
- In the console first: paste the fetch above and explore the
dataobject (click to unfold it): find the current temperature and the weather description. - In your page: a "Weather" button and a
<p id="weather">. On click, fetch, then display "It is X °C in Paris" in the paragraph. Success criterion: the click shows the real current temperature — compare with wttr.in/Paris in a tab. - Add the
.catchthat displays "Service unavailable" in the paragraph. Test it: cut the network (the dev tools' offline mode), click — the message appears instead of silence. - Change the city in the URL to yours. Watch out for spaces:
New%20York— URLs dislike spaces.
Agent tips: "read this JSON and tell me the path to the temperature", pasting an EXTRACT of the response (not 200 lines). Trap: without the extract, it invents the API's structure. Proof: print data in the console and follow its path with your finger.
Recap (10 min)
Three lines: what an API and JSON are, the fetch/then/then/catch chain, what asynchronous means. Then redo the weather call from memory.
Day 41 — Dark-mode toggle with memory
Goal: add a light/dark toggle button that survives reload thanks to localStorage.
Theory (20 min)
On day 26, dark mode followed the system setting. Today, the user chooses, and the site remembers. Two mechanisms:
First, the toggle: a CSS class on <body> that redefines your variables, and JavaScript adds or removes it:
/* CSS */
body.dark {
--bg: #17181c;
--text: #e8e6e3;
}
/* JS */
document.querySelector("#toggle").addEventListener("click", function () {
document.body.classList.toggle("dark");
});
classList.toggle adds the class if absent, removes it if present: one line for a switch.
Then, the memory: localStorage is a small per-site storage in the browser that survives closing. Two methods: localStorage.setItem("theme", "dark") writes, localStorage.getItem("theme") reads back (null if never written). When the script loads, read and apply:
if (localStorage.getItem("theme") === "dark") {
document.body.classList.add("dark");
}
You see the limit: this choice lives only in THIS browser, on THIS device. No account, no server — for a static site, exactly what you need.
Practice (30 min)
- Add the CSS rule
body.dark(with your day-26 dark colors) and a<button id="toggle">Dark mode</button>in your header. - Hook the toggle listener. Success criterion 1: the click flips the theme, and clicking again comes back.
- In the listener, after the toggle, write the preference: read
document.body.classList.contains("dark")and store "dark" or "light". At load, read back and apply. - Success criterion 2: switch to dark, reload the page (F5): the dark theme is still there. Close the tab, reopen: still there.
- Open the dev tools, Application (or Storage) tab → Local Storage: see your
themekey and its value. Delete it, reload: back to light. - If time remains, give yesterday's todo list the same gift:
localStorage.setItem("todos", JSON.stringify(todos))on every change, andJSON.parseat load. JSON.stringify turns the array into storable text; JSON.parse does the reverse.
Agent tips: "add a persistent dark-mode toggle with localStorage" is a classic that delegates well. Trap: it may forget to apply the theme AT LOAD — the choice survives only one reload. Proof: flip, reload, close, reopen. Three steps, not one.
Recap (10 min)
Three lines: toggle, setItem/getItem, the limit of local storage. Then redo the complete toggle from memory.
Day 42 — Module 3 review
Goal: check the JavaScript skills before the final project.
Theory (20 min)
Test yourself without notes:
- const or let: which by default, and why?
- What is
"5" + 3, and how do you get 8? - Difference between
console.logandreturnin a function? - What is the DOM, and what does
querySelector(".x")do when nothing matches? - Name the three parts of an
addEventListener. - Why
textContentrather thaninnerHTMLfor user input? - Describe the state / render / actions architecture of the todo list.
- What does
event.preventDefault()do on a submit?
Practice (30 min)
- Take the eight-question test in writing, without notes.
- For each failed question, redo the practice of the matching session.
- Success criterion: eight right answers, or the sessions redone.
- Timed drill: in twenty minutes, on a blank page, rebuild the day-35 counter without looking at your notes. Time yourself; the gesture must become natural.
- Tidy up: the whole module into your
module3folder, with your enriched me.html, the weather, the todo list, the toggle.
Agent tips: "quiz me on JavaScript: variables, conditions, functions, DOM, events, fetch — one question at a time" makes you an examiner. Trap: it may drift to off-path topics (classes, ES modules). Proof: rein it in with your table of contents pasted.
Recap (10 min)
Three lines: your three skills, the fragile notion. Tomorrow: accessibility, performance, and going online — your work meets the world.
Found this useful? Tell us what to measure next.
Comments
No account, no tracker: a comment is read by a human before it appears.