Week 4 - Data structures and loops

Arrays

Loops

Objects

Manipulating Data Structures

Package managers

Tools (IDE code editing)

Style - Autoformatting

Practice

Assignment

Back to core program

Modern JavaScript provides powerful tools for working with arrays and objects without mutating the originals. The spread operator and destructuring let you copy, combine, and extract data cleanly.

Spread operator

The spread operator (...) allows you to copy properties from one object to another or merge multiple objects (later properties override earlier ones):

Creating object copies

The spread operator (...) creates a shallow copy of an object:

const user = {
  name: 'Alice',
  age: 28
};

const userCopy = { ...user };
console.log(userCopy);  // { name: 'Alice', age: 28 }

The copy is independent, so changes to one don't affect the other:

userCopy.age = 30;
console.log(user.age);      // 28 (unchanged)
console.log(userCopy.age);  // 30

Adding properties while copying

You can add new properties during the spread operation:

const user = {
  name: 'Alice',
  age: 28
};

const extendedUser = {
  ...user,
  email: '[email protected]',
  isActive: true
};

console.log(extendedUser);
// { name: 'Alice', age: 28, email: '[email protected]', isActive: true }

Overriding properties

Properties that come later in the spread override earlier ones:

const user = {
  name: 'Alice',
  age: 28
};

const updatedUser = {
  ...user,
  age: 29  // Overrides age from user
};

console.log(updatedUser);  // { name: 'Alice', age: 29 }

Order matters: the last value wins when property names conflict.

Merging objects

Combine multiple objects by spreading them in sequence:

const defaults = {
  theme: 'light',
  language: 'en',
  notifications: true
};

const userPreferences = {
  theme: 'dark'
};

const settings = {
  ...defaults,
  ...userPreferences
};

console.log(settings);
// { theme: 'dark', language: 'en', notifications: true }

User preferences override defaults because they're spread last. This pattern is useful for configuration objects where you want defaults with custom overrides.

<aside> ⚠️

The spread operator creates a shallow copy. This means only the top level of the object is copied. Nested objects or arrays inside remain references to the originals.

</aside>

Understanding shallow copies

When you spread an object with nested structures, the nested parts aren't truly copied:

const original = {
  name: 'Alice',
  address: {
    city: 'Amsterdam'
  }
};

const copy = { ...original };

At this point, name is copied, but address is just a reference to the same object in memory.

Modifying nested objects

Changes to nested objects affect both the original and the copy:

copy.address.city = 'Rotterdam';

console.log(original.address.city);  // 'Rotterdam' (changed!)
console.log(copy.address.city);      // 'Rotterdam'

Both point to the same address object, so modifying one modifies both.

Top-level properties work as expected

Properties at the root level are independent:

copy.name = 'Bob';

console.log(original.name);  // 'Alice' (unchanged)
console.log(copy.name);      // 'Bob'

The name property was truly copied, so changing it in the copy doesn't affect the original.

Why this happens

Think of it like photocopying a document that contains a reference to another document. The photocopy includes the reference, but both copies point to the same second document. They don't create a separate copy of that second document.

Destructuring

Destructuring allows you to extract properties from objects into variables with a clean, concise syntax.

<aside> 💡

Destructuring, spread operator, and property shorthand are modern JavaScript features you'll see everywhere in React, Node.js, and contemporary codebases. Learning them now will make reading other people's code much easier!

</aside>

const user = {
  name: 'Alice',
  age: 28,
  city: 'Amsterdam'
};

// Traditional way
const name = user.name;
const age = user.age;
const city = user.city;

// Destructuring - extract multiple properties at once
const { name, age, city } = user;
console.log(name);  // 'Alice'
console.log(age);   // 28
console.log(city);  // 'Amsterdam'

You can even customize the variable names you extract, provide default values, and destructure nested objects!

// Rename variables
const { name: userName, age: userAge } = user;
console.log(userName);  // 'Alice'

// Default values for missing properties
const { name, country = 'Unknown' } = user;
console.log(country);  // 'Unknown'

// Extract only what you need
const { name } = user;  // Just get name, ignore rest

// Nested destructuring
const response = {
  data: {
    user: {
      id: 123,
      profile: {
        name: 'Alice',
        email: '[email protected]'
      }
    }
  }
};

const { data: { user: { profile: { name, email } } } } = response;
console.log(name);   // 'Alice'
console.log(email);  // '[email protected]'

It is really helpful when using function parameters:

// Instead of accessing properties inside function
function greet(user) {
  console.log(`Hello, ${user.name}! You are ${user.age} years old.`);
}

// Destructure in parameter (cleaner)
function greet({ name, age }) {
  console.log(`Hello, ${name}! You are ${age} years old.`);
}

greet({ name: 'Alice', age: 28 });
// Hello, Alice! You are 28 years old.

// With default values
function createUser({ name, age, role = 'user' }) {
  return { name, age, role };
}

console.log(createUser({ name: 'Bob', age: 25 }));
// { name: 'Bob', age: 25, role: 'user' }

<aside> ⌨️

Create an object with properties for a book (title, author, year, pages). Use destructuring to extract title and author into variables. Then create a function that takes a book object as parameter and uses destructuring in the parameter list.

</aside>

Additional resources

Reading


CC BY-NC-SA 4.0 Icons

*https://hackyourfuture.net/*

Found a mistake or have a suggestion? Let us know in the feedback form.