Course outline
Full-Stack course / JavaScript fundamentals

Merge user settings

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-04-merge-user-settings
cd 03-04-merge-user-settings
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.

Merge user settings

Write a function that combines a user's saved settings with the app's defaults, and a second function that reads two fields out of a settings object with sensible defaults.

Worked example

Here's a similar pair of functions for a coffee shop's ordering app:

const defaultOrder = { size: "medium", milk: "whole", shots: 1, syrup: "none" };

function mergeOrder(defaults, customization) {
  return { ...defaults, ...customization };
}

function sizeAndShots(order) {
  const { size = "medium", shots = 1 } = order;
  return [size, shots];
}

const customOrder = mergeOrder(defaultOrder, { size: "large", syrup: "vanilla" });
console.log(customOrder);
console.log(defaultOrder);
console.log(sizeAndShots(customOrder));
console.log(sizeAndShots({}));
{ size: 'large', milk: 'whole', shots: 1, syrup: 'vanilla' }
{ size: 'medium', milk: 'whole', shots: 1, syrup: 'none' }
[ 'large', 1 ]
[ 'medium', 1 ]

mergeOrder spreads defaults into a brand-new object first, then spreads customization on top of it - any field customization sets overwrites the default, and any field it leaves out keeps the default's value. Neither defaultOrder nor the customization object is touched; customOrder is a third, separate object. sizeAndShots then destructures two fields out of whatever settings object it's handed, with its own fallbacks for when a field is missing entirely - notice it works even on {}, an order with nothing customized at all.

Your task

Write function mergeSettings(defaults, saved). Return a brand-new object containing every field from defaults, with any field also present in saved overwritten by saved's value. A field that exists in saved but not in defaults should still appear in the result. Neither defaults nor saved should be changed by calling this function.

Write function themeAndVolume(settings). Using destructuring with defaults, return [theme, volume], where theme falls back to "light" if settings.theme is missing, and volume falls back to 50 if settings.volume is missing.

Rules

  • mergeSettings returns a different object than both defaults and saved - never one of the originals, mutated or otherwise reused.
  • saved wins on any field it shares with defaults; fields only in defaults keep their default value, and fields only in saved are carried over too.
  • themeAndVolume's fallbacks only apply when the field is genuinely missing (undefined) - they're defaults for an absent value, not a replacement for every falsy one.

What you'll practice

Combining two objects with spread so the second one's fields win, and destructuring specific fields out of an object with defaults for whichever ones aren't there.

Run it

gonomicon fetch fs-week-2/03-04-merge-user-settings
cd 03-04-merge-user-settings
gonomicon test
gonomicon submit

Hints

  1. mergeSettings is one line: spread defaults first, then spread saved on top of it, so saved's fields win.
  2. themeAndVolume is destructuring with defaults, the same shape you've seen for function parameters: const { theme = "light", volume = 50 } = settings;
  3. Build the merged settings object with spread before you destructure out of it - the two functions don't need to know about each other, but mergeSettings runs first in the tests.