Checkpoint: Favourites

The Course
•
3 min read

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.

Predict, then run JavaScript
const first = ["a"];
const copy = [...first];

copy.push("b");
console.log(first.length);
Check your prediction
1

A 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 tryWhat your result should demonstrate
Two factoriesKeep their item sets independent
Duplicate add to one instanceFollow the documented uniqueness policy
Caller edits a snapshotInternal 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

Exercise

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.

Your working space JavaScript
// 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
0

Add 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?

Was this article helpful?

Your response is saved on this device.