JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
42: Spread and Rest Syntax
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:
- Create an object
baseStatswithstrength: 10,agility: 10, andintellect: 10. - Create an object
gearBonuswithstrength: 5andagility: 2. - Write a function called
calculateFinalStatsthat accepts thebaseStats, thegearBonus, and a rest parameter calledbuffs. - Inside the function:
- Use spread syntax to merge
baseStatsandgearBonusinto a new object. - Use a loop or
reduceto add the sum of all values in thebuffsarray to thestrengthproperty of the merged object. - Return the final object.
- Use spread syntax to merge
Test your code with: calculateFinalStats(baseStats, gearBonus, 2, 3, 1). The final strength should be 18 (10 base + 5 gear + 2 + 3 + 1 buffs).
There are no comments for now.