Start with what you know
This course assumes you can use variables, branches, loops, arrays of records, functions, map/filter, basic tests, and a small HTML form. You do not need promises, modules, classes, or a framework yet. If you cannot build the beginner reading report without copying, revisit the independent beginner brief first. Needing a refresher is normal.
The new goal is a reading queue: search a catalogue, validate its results, save selected books, and keep the interface correct when requests overlap or fail. We will begin with small functions so each later moving part has a clear job. Most examples use deterministic local data; an unreliable public API should not decide whether you can finish a lesson.
Check the bridge from beginner
You already have the building blocks. These are the specific beginner skills we will reuse:
| Skill | Where to refresh it |
|---|---|
| Return values, map, and filter | Beginner functions and callbacks |
| Arrays of records and shallow copies | Beginner records and references |
| Throwing, catching, and checking results | Beginner debugging and tests |
| A form changing state and updating text | Beginner forms; needed again from intermediate Day 5 |
You do not need to recognize every new symbol on later pages. This course introduces destructuring, promises, modules, and request lifecycles before using them in the project.
Readiness check: reuse your study-plan skills
Before learning the new book model, write openTopics(sessions). Return an array of topic names for incomplete sessions, without changing any records. Print Arrays and confirm the first original record is still done. You may use a loop or map/filter. If you need the solution, refresh the linked beginner explanation and try again with new values.
const sessions = [
{ topic: "Loops", done: true },
{ topic: "Arrays", done: false }
];
// Define openTopics, print its joined result, then inspect sessions[0].done.Hint 1: the idea
Select the incomplete records before turning records into names.
Hint 2: a first step
Use a condition on done for selection and the topic field for the result. Neither step needs to assign to a record.
Show one solution
function openTopics(sessions) {
const open = sessions.filter(session => !session.done);
return open.map(session => session.topic);
}
const sessions = [
{ topic: "Loops", done: true },
{ topic: "Arrays", done: false }
];
console.log(openTopics(sessions).join(", "));
console.log(sessions[0].done);Arrays
trueTry an empty list and an all-completed list. Both return an empty array. This is a readiness check for the familiar skills, not a test of material we have not taught yet.
Say what a function promises
A contract describes accepted inputs, returned outputs, changes to input, and failures. “Adds a book” is incomplete. “Given valid books with unique ids and one valid book, return a list containing that id once; create a new list only when adding it and preserve the input” is testable. An id is a stable string identifying one book, independent of its position or title.
The function below assumes its records are valid. Validation is a separate boundary we will add on Day 1. A duplicate id leaves the original list unchanged. Returning the same array in that case is intentional; a new array is only needed for a changed value.
Keep each editor self-contained. JavaScript console editors have no DOM or permanent files; the webpage labs and module examples explicitly use their own environments. Spend the proposed study time tracing and changing code, not only reading it.
Predict and trace
Write the output before running. Follow the values through each call; if your prediction differs, identify the first step that surprised you.
function saveOnce(saved, book) {
if (saved.some(item => item.id === book.id)) {
return saved;
}
return [...saved, { ...book }];
}
const first = [{ id: "js", title: "JavaScript Notes" }];
const next = saveOnce(first, { id: "web", title: "The Web" });
console.log(first.length);
console.log(next.length);
console.log(saveOnce(next, next[0]).length);Check your prediction
1
2
2some asks whether any id matches. The array and added record are copied; the existing records are shared because this function does not edit them.
Build it yourself
Function Contracts: practise
Write hasBook(books, id), returning a boolean. Check an existing id, a missing id, and an empty list. Print the three answers.
const books = [{ id: "js", title: "Notes" }];
// Define hasBook and check three cases.Hint 1: the idea
Search by stable id, not by the array position.
Hint 2: a first step
Use some with a callback comparing item.id to the id parameter.
Show one solution
function hasBook(books, id) {
return books.some(book => book.id === id);
}
const books = [{ id: "js", title: "Notes" }];
console.log(hasBook(books, "js"));
console.log(hasBook(books, "missing"));
console.log(hasBook([], "js"));true
false
falseChange the title while keeping the id. Membership should not change. State whether this helper validates malformed records or expects already-valid input.
Test a changed requirement
Change the title while keeping the id. Membership should not change. State whether this helper validates malformed records or expects already-valid input.
Explain before moving on
Explain why a title is a poor identity and which objects saveOnce copies. Describe one input your contract excludes.
Completion is saved in this browser only. It does not measure mastery.