Lesson 8: Objects - Storing Related Data

What You'll Learn

  • What objects are and when to use them
  • How to create and access object properties
  • How to add, modify, and delete properties
  • Object methods (functions inside objects)
  • How to work with nested objects
  • Object destructuring

Why This Matters

Objects let you group related data together. Instead of having separate variables for userName, userAge, userEmail, you can have one user object that contains all this information. This makes your code more organized and easier to manage.

---

Part 1: What is an Object?

An object is a collection of key-value pairs. Think of it like:

  • A dictionary: word (key) → definition (value)
  • A person's profile: name, age, email, etc.
  • A product: title, price, description, inStock

---

Part 2: Creating Objects

Create a new file: lesson-08/objects.js

Object Literal Syntax

const person = {
  name: "Alice",
  age: 30,
  city: "New York"
};

console.log(person);
// Output: { name: 'Alice', age: 30, city: 'New York' }

With Type Annotations

const person: {
  name;
  age;
  city;
} = {
  name: "Alice",
  age: 30,
  city: "New York"
};

Creating Multiple Objects with Same Structure

In JavaScript, you often create multiple objects with the same properties:

const alice = {
  name: "Alice",
  age: 30,
  city: "New York"
};

const bob = {
  name: "Bob",
  age: 25,
  city: "Los Angeles"
};

const charlie = {
  name: "Charlie",
  age: 35,
  city: "Chicago"
};

All three objects have the same structure (name, age, city), which is a common pattern in JavaScript.

---

Part 3: Accessing Object Properties

There are two ways to access properties:

Dot Notation (Most Common)

const car = {
  brand: "Toyota",
  model: "Camry",
  year: 2022
};

console.log(car.brand);  // Toyota
console.log(car.model);  // Camry
console.log(car.year);   // 2022

Bracket Notation

const car = {
  brand: "Toyota",
  model: "Camry",
  year: 2022
};

console.log(car["brand"]);  // Toyota
console.log(car["model"]);  // Camry
console.log(car["year"]);   // 2022

When to Use Bracket Notation

// 1. When property name has spaces or special characters
const obj = {
  "first name": "Alice",
  "user-id": 123
};

console.log(obj["first name"]);  // Alice
// obj.first name  // ❌ Syntax error

// 2. When property name is in a variable
const propertyName = "brand";
console.log(car[propertyName]);  // Toyota

// 3. When property name is dynamic
const key = "age";
const person = { name: "Bob", age: 25 };
console.log(person[key]);  // 25

---

Part 4: Modifying Objects

Changing Property Values

const user = {
  name: "Alice",
  age: 30,
  isActive: true
};

console.log(user.age);  // 30

// Change a property
user.age = 31;
console.log(user.age);  // 31

user.isActive = false;
console.log(user.isActive);  // false

Adding New Properties

const person = {
  name: "Bob"
};

console.log(person);  // { name: 'Bob' }

// Add new property
person.age = 25;
person.city = "Boston";

console.log(person);  // { name: 'Bob', age: 25, city: 'Boston' }
Note: JavaScript objects are dynamic - you can add properties at any time!

Deleting Properties

const user = {
  name: "Charlie",
  age: 28,
  tempData: "temporary"
};

console.log(user);  // { name: 'Charlie', age: 28, tempData: 'temporary' }

delete user.tempData;

console.log(user);  // { name: 'Charlie', age: 28 }

---

Part 5: Object Methods

Objects can contain functions, called methods:

const calculator = {
  add: function(a, b) {
    return a + b;
  },
  subtract: function(a, b) {
    return a - b;
  }
};

console.log(calculator.add(5, 3));       // 8
console.log(calculator.subtract(10, 4)); // 6

Shorthand Method Syntax

const calculator = {
  add(a, b) {
    return a + b;
  },
  subtract(a, b) {
    return a - b;
  }
};

console.log(calculator.add(5, 3));  // 8

Using 'this' Keyword

The this keyword refers to the object itself:

const person = {
  firstName: "Alice",
  lastName: "Johnson",
  age: 30,
  
  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  },
  
  greet() {
    console.log(`Hello, I'm ${this.getFullName()} and I'm ${this.age} years old.`);
  }
};

console.log(person.getFullName());  // Alice Johnson
person.greet();  // Hello, I'm Alice Johnson and I'm 30 years old.
What is this? Inside a method, this refers to the object that owns the method.

---

Part 6: Nested Objects

Objects can contain other objects:

const student = {
  name: "Emma",
  age: 20,
  address: {
    street: "123 Main St",
    city: "Boston",
    zipCode: "02101"
  },
  grades: {
    math: 95,
    english: 88,
    science: 92
  }
};

// Access nested properties
console.log(student.address.city);       // Boston
console.log(student.grades.math);        // 95
console.log(student.address.zipCode);    // 02101

Deep Nesting

const company = {
  name: "TechCorp",
  employees: {
    engineering: {
      lead: "Alice",
      members: 15
    },
    sales: {
      lead: "Bob",
      members: 10
    }
  }
};

console.log(company.employees.engineering.lead);  // Alice
console.log(company.employees.sales.members);     // 10

---

Part 7: Arrays of Objects

Very common pattern - store multiple similar objects in an array:

const products = [
  { id: 1, name: "Laptop", price: 999, inStock: true },
  { id: 2, name: "Mouse", price: 25, inStock: true },
  { id: 3, name: "Keyboard", price: 75, inStock: false }
];

// Loop through array of objects
for (const product of products) {
  console.log(`${product.name}: $${product.price}`);
}

// Output:
// Laptop: $999
// Mouse: $25
// Keyboard: $75

Finding an Object in an Array

const users = [
  { id: 1, name: "Alice", age: 30 },
  { id: 2, name: "Bob", age: 25 },
  { id: 3, name: "Charlie", age: 35 }
];

// Find user with id 2
function findUserById(users[], id) {
  for (const user of users) {
    if (user.id === id) {
      return user;
    }
  }
  return null;
}

const user = findUserById(users, 2);
console.log(user);  // { id: 2, name: 'Bob', age: 25 }

---

Part 8: Object Destructuring

Destructuring lets you extract properties into variables:

Basic Destructuring

const person = {
  name: "Alice",
  age: 30,
  city: "New York"
};

// Old way
const name = person.name;
const age = person.age;
const city = person.city;

// New way (destructuring)
const { name, age, city } = person;

console.log(name);  // Alice
console.log(age);   // 30
console.log(city);  // New York

Renaming Variables

const user = {
  name: "Bob",
  age: 25
};

// Rename during destructuring
const { name: userName, age: userAge } = user;

console.log(userName);  // Bob
console.log(userAge);   // 25

Default Values

const settings = {
  theme: "dark"
};

// Provide default if property doesn't exist
const { theme, fontSize = 16 } = settings;

console.log(theme);     // dark
console.log(fontSize);  // 16 (default value)

Destructuring in Function Parameters

// Instead of this:
function greetUser(user) {
  console.log(`Hello ${user.name}, you are ${user.age} years old.`);
}

// Use destructuring:
function greetUser2({ name, age }) {
  console.log(`Hello ${name}, you are ${age} years old.`);
}

const user = { name: "Alice", age: 30, email: "alice@example.com" };
greetUser2(user);  // Hello Alice, you are 30 years old.

---

Part 9: Checking Properties

Check if Property Exists

const person = {
  name: "Alice",
  age: 30
};

// Using 'in' operator
console.log("name" in person);   // true
console.log("email" in person);  // false

// Using hasOwnProperty
console.log(person.hasOwnProperty("age"));    // true
console.log(person.hasOwnProperty("email"));  // false

Optional Properties

In JavaScript, object properties are naturally optional. You can access properties that might not exist:

const user1 = { name: "Alice", age: 30, email: "alice@example.com" };
const user2 = { name: "Bob", age: 25 };  // No email property

// Safe access with optional chaining
console.log(user1.email);  // alice@example.com
console.log(user2.email);  // undefined

---

Part 10: Practical Examples

Example 1: Shopping Cart

// Cart items structure
const cart = [
  { id: 1, name: "Laptop", price: 999, quantity: 1 },
  { id: 2, name: "Mouse", price: 25, quantity: 2 }
];

function calculateTotal(cart) {
  let total = 0;
  for (const item of cart) {
    total += item.price * item.quantity;
  }
  return total;
}

console.log(`Total: $${calculateTotal(cart)}`);  // Total: $1049

Example 2: Student Grade Manager

const student = {
  name: "Emma",
  grades: [85, 90, 78, 92, 88],
  
  getAverage() {
    const sum = this.grades.reduce((acc, grade) => acc + grade, 0);
    return sum / this.grades.length;
  }
};

console.log(`${student.name}'s average: ${student.getAverage()}`);
// Emma's average: 86.6

Example 3: User Authentication

const users = [
  { username: "alice", password: "pass123", isActive: true },
  { username: "bob", password: "secret", isActive: false }
];

function login(username, password) {
  for (const user of users) {
    if (user.username === username && user.password === password) {
      if (user.isActive) {
        user.lastLogin = new Date();
        console.log("Login successful!");
        return true;
      } else {
        console.log("Account is inactive.");
        return false;
      }
    }
  }
  console.log("Invalid credentials.");
  return false;
}

login("alice", "pass123");  // Login successful!

---

Practice Exercises

Exercise 1: Create a Book Object

Create a book object with title, author, pages, and a method that returns a description.

Exercise 2: Array of Products

Create an array of products and write functions to:

  • Find the most expensive product
  • Filter products by price range
  • Count in-stock products

Exercise 3: Address Book

Create an address book (array of contacts) with name, phone, and email. Write functions to:

  • Add a contact
  • Search by name
  • Delete a contact

Exercise 4: Bank Account

Create a bank account object with balance and methods to deposit, withdraw, and get balance.

Exercise 5: Recipe Manager

Create a recipe object with ingredients (array of objects) and steps. Calculate total cost.

---

Common Mistakes

Mistake 1: Accessing Non-Existent Property

const person = { name: "Alice", age: 30 };

console.log(person.email);  // undefined (not an error, but probably not what you want)

// Better: Check first
if ("email" in person) {
  console.log(person.email);
} else {
  console.log("No email available");
}

Mistake 2: Modifying Objects Unintentionally

const original = { count: 0 };
const copy = original;  // ⚠️ This doesn't create a copy!

copy.count = 5;

console.log(original.count);  // 5 (original was changed too!)

// To create a real copy:
const realCopy = { ...original };  // Spread operator

Mistake 3: Forgetting 'this'

const person = {
  name: "Alice",
  greet() {
    console.log(`Hello, ${name}`);  // ❌ name is not defined
  }
};

// Fix: Use this
const person = {
  name: "Alice",
  greet() {
    console.log(`Hello, ${this.name}`);  // ✅ Correct
  }
};

---

Key Concepts Summary

Concept Description Example
Object Collection of key-value pairs { name: "Alice", age: 30 }
Property A key-value pair in object name: "Alice"
Method Function inside object greet() { }
this Refers to the object this.name
Destructuring Extract properties to variables const { name, age } = obj

What You Learned

  • ✅ How to create objects with properties
  • ✅ How to access and modify object properties
  • ✅ How to create methods (functions in objects)
  • ✅ How to use the this keyword
  • ✅ How to work with nested objects
  • ✅ How to work with arrays of objects
  • ✅ How to use object destructuring
  • ✅ How to check if properties exist

What's Next?

In the next lesson, you'll learn about advanced object patterns - destructuring, spreading, factory functions, and validation techniques!