Course outline
Full-Stack course / JavaScript fundamentals

Clone game state

Lab

How to fetch and submit this exercise

Once: install the tool and connect your account.

curl -fsSL https://gonomicon.com/install.sh | sh
gonomicon login

Each exercise: download it, edit the file named in the instructions, then submit.

gonomicon fetch fs-week-2/03-06-clone-game-state
cd 03-06-clone-game-state
gonomicon submit

The runner depends on the exercise: JavaScript/TypeScript/React labs run with Vitest, Python labs with pytest, and config-file labs (Docker, CI, Terraform, Nginx) are checked by parsing your file. gonomicon test runs the visible checks on your computer first; submitting also runs the hidden checks on our server.

Clone game state

Write one function that makes a completely independent copy of a nested game-state object, so changing the copy never touches the original.

Worked example

Here's a similar function for a trip-planning app's itinerary:

function cloneItinerary(itinerary) {
  return structuredClone(itinerary);
}

const itinerary = {
  trip: { title: "Pacific Coast", dates: { start: "2025-06-01", end: "2025-06-10" } },
  stops: [
    { city: "Seattle", nights: 2 },
    { city: "Portland", nights: 3 },
  ],
};

const copy = cloneItinerary(itinerary);
copy.trip.dates.end = "2025-06-12";
copy.stops[0].nights = 5;

console.log(itinerary.trip.dates.end);
console.log(itinerary.stops[0].nights);
console.log(copy.trip.dates.end);
console.log(copy.stops[0].nights);
2025-06-10
2
2025-06-12
5

cloneItinerary hands the whole object to structuredClone(), which walks every nested object and array - trip, trip.dates, each entry in stops - and builds a brand-new, fully separate version of all of it. Editing copy.trip.dates.end three levels deep, or an item inside copy.stops, never touches itinerary at all, which is exactly what a plain { ...itinerary } spread couldn't guarantee once there's nesting involved.

Your task

Write function cloneState(state). state is shaped like { player: { name, stats: { hp, level } }, inventory: [...] }, where inventory is an array of item objects. Return a deep, independent copy of state using structuredClone.

Rules

  • The returned copy must start out deeply equal to the state it was given.
  • Editing any nested field on the copy - the player's name, a stat, or a field on an item inside inventory - must never change the original state object.
  • Adding or removing an item from the copy's inventory array must never change the length or contents of the original state.inventory.
  • cloneState doesn't change state itself while making the copy.

What you'll practice

Reaching for structuredClone() instead of spread whenever a copy has to survive edits to its nested objects and arrays, and checking independence by actually editing deep into both the original and the copy.

Run it

gonomicon fetch fs-week-2/03-06-clone-game-state
cd 03-06-clone-game-state
gonomicon test
gonomicon submit

Hints

  1. Spread ({ ...state }) only copies the outer slots - player, stats and inventory would still be shared addresses, not real copies.
  2. structuredClone(state) is the whole function body - it walks every nested object and array and duplicates all of it in one call.
  3. Test yourself by editing a deeply nested field on the clone (like copy.player.stats.hp) and checking the original state object didn't move.