Skip to Content
Course content

42: Spread and Rest Syntax

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was working on a user settings module the other day and ran into a classic headache: merging a set of default configuration options with the specific overrides a user has saved in their profile. I wanted to create a final "active" settings object without mutating the original defaults, because mutating global defaults is a one-way ticket to debugging nightmares.

The struggle with merging objects

At first, I tried something simple. I had my defaults and my user overrides, and I thought I'd just combine them. But look at what happens when we do this the old-fashioned way:

const defaultSettings = { theme: 'light', notifications: true, fontSize: 14 };
const userSettings = { theme: 'dark', fontSize: 18 };

// I want a combined version...
const activeSettings = defaultSettings;
activeSettings.theme = userSettings.theme;

console.log(defaultSettings.theme); // 'dark'

Wait. I just changed the defaultSettings object itself. That's exactly what I wanted to avoid. I need a new object that contains everything from the defaults, but with the user's preferences layered on top. This is where the spread syntax (the three dots ...) becomes a lifesaver.

const defaultSettings = { theme: 'light', notifications: true, fontSize: 14 };
const userSettings = { theme: 'dark', fontSize: 18 };

const activeSettings = { ...defaultSettings, ...userSettings };

console.log(activeSettings); 
// { theme: 'dark', notifications: true, fontSize: 18 }

console.log(defaultSettings.theme); 
// 'light' - Still intact!

By using ...defaultSettings, I'm essentially telling JavaScript: "Take every single key-value pair inside this object and unpack them right here into this new object." Since I put ...userSettings second, any keys that overlap (like theme) get overwritten by the later one. It's clean, it's declarative, and it doesn't destroy my original data.

Expanding lists without the boilerplate

I realized this works for arrays too. Let's say I have a list of "featured" product IDs and a list of "regular" product IDs, and I need one master list to send to the API. In the past, I would have used concat(), but that feels a bit clunky now.

const featured = ['p1', 'p2'];
const regular = ['p3', 'p4', 'p5'];

const allProducts = [...featured, ...regular, 'p6']; 
// I can even throw in a single item at the end

console.log(allProducts); 
// ['p1', 'p2', 'p3', 'p4', 'p5', 'p6']

The logic is identical: I'm "spreading" the elements of the arrays into a new array. Honestly, once you get used to this, concat feels like writing a formal letter when a text message will do.

Collecting the leftovers

Now, here is where it gets confusing. The three dots ... are also used for something called "Rest" syntax. It looks exactly the same, but it does the opposite. While spread unpacks an array into individual elements, rest gathers individual elements into an array.

I noticed this while writing a function to calculate the total price of a shopping cart. I didn't know if the user would pass in two items or twenty.

function calculateTotal(tax, ...items) {
    console.log(tax);   // 0.07
    console.log(items); // ['apple', 'bread', 'milk']
}

calculateTotal(0.07, 'apple', 'bread', 'milk');

By putting ...items in the function parameters, I'm telling JavaScript: "Take the first argument and assign it to tax, and then take everything else that comes after it and bundle it into an array called items."

One rule I learned the hard way: the rest parameter must be the last one in the list. You can't do (...items, tax) because JavaScript wouldn't know where the "rest" ends and the "tax" begins. It would just be chaos.




📋 Practical Task

Build a RPG Character Stat Merger

You are building a character system for an RPG. You have a base set of stats, a set of bonuses provided by equipped gear, and a variable number of temporary "buffs" (numeric modifiers) applied by spells.

Your Task:

  1. Create an object baseStats with strength: 10, agility: 10, and intellect: 10.
  2. Create an object gearBonus with strength: 5 and agility: 2.
  3. Write a function called calculateFinalStats that accepts the baseStats, the gearBonus, and a rest parameter called buffs.
  4. Inside the function:
    • Use spread syntax to merge baseStats and gearBonus into a new object.
    • Use a loop or reduce to add the sum of all values in the buffs array to the strength property of the merged object.
    • Return the final object.

Test your code with: calculateFinalStats(baseStats, gearBonus, 2, 3, 1). The final strength should be 18 (10 base + 5 gear + 2 + 3 + 1 buffs).

Rating
0 0

There are no comments for now.

to be the first to leave a comment.