Own a small list
Build createFavourites(), returning add(id) and snapshot(). add appends an id only once. snapshot returns a copy so a caller cannot modify the store’s internal array. Inputs are already-valid strings. Each factory call must own an independent list.
Before coding, list the three ways a weak implementation could fail: repeated ids, shared state across factories, or a caller mutating a returned array. Write a check for each. Reuse the small assertion pattern from today rather than relying only on inspecting an object in a console.
Take about 15 minutes to plan, attempt, and test. If you need the hints, close them afterward and rebuild with a different record type. Explain which parts could be exported from a module without any DOM access.
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.
const first = ["a"];
const copy = [...first];
copy.push("b");
console.log(first.length);Check your prediction
1A copied array protects the container from this push. It would not clone nested objects.
Acceptance cases before you code
Write a small test plan before implementing closure store ownership. These cases extend the brief; they are not a second worked solution. Predict the expected behavior independently, then test through the public function. A good ordinary example and a good boundary example should catch different possible mistakes.
| Case to try | What your result should demonstrate |
|---|---|
| Two factories | Keep their item sets independent |
| Duplicate add to one instance | Follow the documented uniqueness policy |
| Caller edits a snapshot | Internal container stays unchanged |
After the core task passes, deliberately break one rule and identify the case that notices it. Restore the implementation and explain the failure in terms of the contract, not the number of assertions. If a case requires a concept you have not recalled, revisit the relevant lesson before opening the solution.
Build it yourself
Checkpoint: Favourites: practise
Implement the factory. Add a twice to one instance, edit a snapshot, and verify the store still has one item while a second instance stays empty.
// Return methods using the local array; avoid this and global variables.Hint 1: the idea
Place the array inside the factory but outside both methods.
Hint 2: a first step
snapshot must copy; add should check includes before push.
Show one solution
function createFavourites() {
const ids = [];
return {
add(id) {
if (!ids.includes(id)) {
ids.push(id);
}
},
snapshot() {
return [...ids];
}
};
}
const first = createFavourites();
const second = createFavourites();
first.add("a");
first.add("a");
const snapshot = first.snapshot();
snapshot.push("outside");
if (first.snapshot().length !== 1) {
throw new Error("snapshot leak");
}
if (second.snapshot().length !== 0) {
throw new Error("shared state");
}
console.log(first.snapshot().join(", "));
console.log(second.snapshot().length);a
0Add a remove method with an unknown-id policy. Test that removing from one instance changes neither the other instance nor an earlier snapshot.
Test a changed requirement
Add a remove method with an unknown-id policy. Test that removing from one instance changes neither the other instance nor an earlier snapshot.
Explain before moving on
Why is a const array appropriate even though add changes it? What would break if snapshot returned ids directly?
Completion is saved in this browser only. It does not measure mastery.