Frontend Master

JavaScript Curriculum

Packaging Related Data
+40 XP

Packaging Related Data

medium
~20 min·40 XP

Every Nexus user has a name, a role, a level, an XP total, a theme preference, and a department. Right now they live in six separate variables that get passed around everywhere together. When a new property gets added, every function that touches users needs updating. There's a structure built for exactly this problem — and it's the foundation of almost everything in JavaScript.

Six variables that belong together

js
const userName = "Alex Chen" const userRole = "engineer" const userLevel = 4 const userIsActive = true const userDepartment = "Platform" const userXp = 1840

Six variables, but they're all about the same thing. Pass them to a function and you're passing six arguments. Add a property and you're updating six call sites. Lose track of which name variable belongs to which user and you've introduced a subtle bug.

An object bundles related data under one name, with labelled slots called properties:

js
const user = { name: "Alex Chen", role: "engineer", level: 4, isActive: true, department: "Platform", xp: 1840, }

One variable. Six properties. Pass user to a function and it gets everything.


Reading properties — two notations

Click any property in the object below. Both access syntaxes update live:

object explorer — click any key6 properties
const user = {
}

dot notation

user.name
"Alex Chen"

Use when the key name is known at write time

bracket notation

user["name"]
"Alex Chen"

Use when the key is in a variable or dynamic

The rule is simple: dot notation by default, bracket notation when the key is dynamic.

js
// Dot — clean, readable, the standard choice console.log(user.name) // "Alex Chen" console.log(user.level) // 4 // Bracket — necessary when the key is in a variable const field = "role" console.log(user[field]) // "engineer" ← dot notation can't do this // Or when the key isn't a valid identifier const config = { "max-retries": 3 } console.log(config["max-retries"]) // 3 ← dashes aren't valid in dot notation

Writing and updating properties

js
// Add a new property user.avatar = "https://nexus.app/avatars/alex.png" // Update an existing property user.level = 5 user.xp = user.xp + 200 // Delete a property delete user.avatar
⚠️Mutating const objects
const means the variable binding can't change — you can't do user = somethingElse. But the object's properties can still be modified. const doesn't make an object immutable; it just prevents reassignment of the variable itself. For immutability you need Object.freeze() or the spread pattern you'll see below.

Destructuring — extract properties cleanly

When you need several properties from an object, destructuring lets you grab them all in one line instead of repeating the object name every time.

Step through both approaches and feel the difference:

destructuring — compare the two styles
4 lines to extract 4 properties
1
const name = user.name
"Alex Chen"
2
const role = user.role
3
const level = user.level
4
const isActive = user.isActive
js
// Full destructuring syntax const { name, role, level, isActive } = user // Now use them directly — no "user." prefix needed console.log(`${name} is a ${role} at level ${level}`) // "Alex Chen is an engineer at level 4"

Rename while destructuring — useful when the property name conflicts with an existing variable:

js
const { name: userName, level: userLevel } = user // userName = "Alex Chen", userLevel = 4 // original property names "name" and "level" are not created as variables

Default values — for properties that might not exist:

js
const { name, badge = "none" } = user // badge = "none" if user.badge is undefined

Spread syntax — composing and updating objects

The spread operator ... copies all properties from one object into another. This is how you update an object without mutating the original — critical for React, state management, and any code that needs predictable data flow.

object spread — merge and override

base — defaults

name:"Alex"
role:"user"will be overridden
theme:"dark"
xp:1840

overrides — applied last

role:"admin"overrides base
level:5
badge:"gold"
const merged = { ...base, ...overrides }
js
// The pattern you'll use constantly in React const user = { name: "Alex", role: "user", level: 4 } // Create a NEW object with one property changed const promoted = { ...user, level: 5 } // { name: "Alex", role: "user", level: 5 } // user is unchanged // Merge two objects — rightmost key wins on conflict const defaults = { theme: "dark", lang: "en", role: "user" } const overrides = { theme: "light", role: "admin" } const config = { ...defaults, ...overrides } // { theme: "light", lang: "en", role: "admin" }
🧠Spread is a photocopy machine
{ ...user } makes a shallow copy — all top-level properties are duplicated into a new object. The original and the copy are independent at the top level. Note "shallow": nested objects inside are still shared references. For deeply nested structures you'd need a deep clone.

Methods — functions as properties

Objects can hold any value — including functions. A function stored on an object is called a method:

js
const user = { name: "Alex Chen", level: 4, xp: 1840, greet() { return `Hi, I'm ${this.name}!` }, levelUp() { return { ...this, level: this.level + 1 } }, } console.log(user.greet()) // "Hi, I'm Alex Chen!" console.log(user.levelUp()) // { name: "Alex Chen", level: 5, xp: 1840, ... }

this inside a method refers to the object the method belongs to. Arrow functions don't have their own this — use regular function syntax for methods that need it.


Nested objects — objects within objects

Real-world data is often nested. An object can hold other objects as property values:

js
const user = { name: "Alex Chen", address: { city: "London", country: "UK", }, preferences: { theme: "dark", language: "en", }, } // Access with chained dot notation console.log(user.address.city) // "London" console.log(user.preferences.theme) // "dark" // Destructure nested values const { address: { city, country } } = user console.log(city) // "London" console.log(country) // "UK"

The immutable update pattern

The single most important object pattern in modern JavaScript — used constantly in React:

js
// NEVER mutate when working with state function updateLevel(user, newLevel) { user.level = newLevel // ✗ mutates original — breaks React, causes bugs return user } // ALWAYS return a new object with spread function updateLevel(user, newLevel) { return { ...user, level: newLevel } // ✓ original untouched, new object returned } const original = { name: "Alex", level: 4 } const updated = updateLevel(original, 5) console.log(original.level) // 4 — untouched console.log(updated.level) // 5 — new value in new object
1Start with original object
2Spread all its properties into a new object
3Override only the changed property
4Return the new object — original is untouched

Your challenge

Build a user object for Jordan — then write promote(user, newLevel) that returns a new object using spread. The test is logging both the original and the result: Jordan should still be level 7, the promoted version should be level 8.

This is the exact pattern you'll use in React state management from day one.

Challenge

Create a user object for a team member called \"Jordan\" — an admin at level 7 with 3420 XP, currently active, working in the Security department. Then write a function called promote(user, newLevel) that returns a NEW object with the level updated (use spread — don't mutate). Call promote with Jordan and level 8, log the original and promoted objects to prove the original didn't change.

objectspropertiesdot-notationbracket-notationdestructuringspreadimmutability
Packaging Related Data | Nexus Learn