Updated Jul 17, 2026

04 - Objects

📋 Jump to Takeaways

🎁 Write a method with an arrow function and this.name suddenly comes back undefined. Why does the arrow break it, and when should you never reach for one?

What are Objects?

Objects store collections of key-value pairs. They're perfect for representing real-world entities with properties.

const person = {
  name: "Alice",
  age: 25,
  city: "NYC"
};

console.log(person.name);  // "Alice"
console.log(person.age);   // 25

Creating Objects

// Object literal (most common)
const user = {
  name: "Bob",
  email: "[email protected]"
};

// Empty object
const empty = {};

// Object constructor (rarely used)
const obj = new Object();
obj.name = "Alice";

Accessing Properties

const person = {
  name: "Alice",
  age: 25,
  "favorite color": "blue"  // property with space
};

// Dot notation (preferred)
console.log(person.name);  // "Alice"

// Bracket notation (for dynamic or special keys)
console.log(person["age"]);            // 25
console.log(person["favorite color"]); // "blue"

// Dynamic access
const key = "name";
console.log(person[key]);  // "Alice"

Adding and Modifying Properties

const person = {
  name: "Alice"
};

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

// Modify existing property
person.name = "Bob";

// Delete property
delete person.city;

console.log(person);  // { name: "Bob", age: 25 }

Methods

Objects can have functions as properties:

const person = {
  name: "Alice",
  age: 25,

  // Method, function as property
  greet: function() {
    console.log(`Hi, I'm ${this.name}`);
  },

  // Shorthand method syntax (modern)
  celebrate() {
    this.age++;
    console.log(`Happy birthday! Now ${this.age}`);
  }
};

person.greet();      // "Hi, I'm Alice"
person.celebrate();  // "Happy birthday! Now 26"

The this Keyword

this refers to the object the method belongs to:

const user = {
  name: "Bob",
  greet() {
    console.log(`Hello, ${this.name}`);
  }
};

user.greet();  // "Hello, Bob"

// Arrow functions don't have their own `this`
// Instead, they inherit `this` from the surrounding scope (in this case, the global scope)
const user2 = {
  name: "Alice",
  greet: () => {
    console.log(this.name);  // ❌ undefined, `this` is the outer scope, not user2
  }
};

// Use regular functions for methods

Object Destructuring

Extract properties into variables:

const person = {
  name: "Alice",
  age: 25,
  city: "NYC"
};

// Destructuring pulls properties into variables in one line
const { name, age, city } = person;
console.log(name);  // "Alice"
console.log(age);   // 25
console.log(city);  // "NYC"

Rename a property as you destructure it:

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

const { name: personName, age: personAge } = person;
console.log(personName);  // "Alice"
console.log(personAge);   // 25

Supply a default for a property that might be missing:

const person = { name: "Alice" };

const { name, country = "USA" } = person;
console.log(country);  // "USA" (fallback)

Collect the leftover properties with the rest operator:

const person = { name: "Alice", age: 25, city: "NYC" };

const { name, ...rest } = person;
console.log(rest);  // { age: 25, city: "NYC" }

Spread Operator with Objects

Copy and merge objects:

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

// Copy object
const copy = { ...person };
console.log(copy);  // { name: "Alice", age: 25 }

// Merge objects
const details = {
  city: "NYC",
  country: "USA"
};

const full = { ...person, ...details };
console.log(full);
// { name: "Alice", age: 25, city: "NYC", country: "USA" }

// Override properties
const updated = {
  ...person,
  age: 26,
  city: "LA"
};
console.log(updated);
// { name: "Alice", age: 26, city: "LA" }

Object Methods

const person = {
  name: "Alice",
  age: 25,
  city: "NYC"
};

// Get all keys
const keys = Object.keys(person);
console.log(keys);  // ["name", "age", "city"]

// Get all values
const values = Object.values(person);
console.log(values);  // ["Alice", 25, "NYC"]

// Get key-value pairs
const entries = Object.entries(person);
console.log(entries);
// [["name", "Alice"], ["age", 25], ["city", "NYC"]]

// Check if property exists
console.log("name" in person);  // true
console.log("email" in person); // false

// hasOwnProperty (safer)
console.log(person.hasOwnProperty("name"));  // true

Iterating Over Objects

JavaScript provides two loop styles that look similar but do very different things:

  • for...in, iterates over the keys (property names). Think "in → index".
  • for...of, iterates over the values (the actual data). Think "of → object values".

You can't use for...of directly on a plain object, it works on iterables like arrays and strings. To use it with objects, pair it with Object.entries(), Object.keys(), or Object.values().

const person = {
  name: "Alice",
  age: 25,
  city: "NYC"
};

// for...in loop
for (const key in person) {
  console.log(`${key}: ${person[key]}`);
}

// Object.entries with for...of (modern)
for (const [key, value] of Object.entries(person)) {
  console.log(`${key}: ${value}`);
}

// Object.keys + forEach
Object.keys(person).forEach((key) => {
  console.log(`${key}: ${person[key]}`);
});

Nested Objects

Objects can contain other objects:

const user = {
  name: "Alice",
  address: {
    street: "123 Main St",
    city: "NYC",
    zip: "10001"
  },
  hobbies: ["reading", "coding"]
};

// Access nested properties
console.log(user.address.city);  // "NYC"
console.log(user.hobbies[0]);    // "reading"

// Optional chaining, safe access to nested properties
console.log(user.address?.city);        // "NYC"
console.log(user.phone?.number);        // undefined (no error)
console.log(user.hobbies?.[0]);         // "reading"

// Destructuring nested objects
const { address: { city, zip } } = user;
console.log(city);  // "NYC"
console.log(zip);   // "10001"

Computed Property Names

Create properties dynamically:

const key = "name";
const value = "Alice";

// Dynamic property
const person = {
  [key]: value
};
console.log(person);  // { name: "Alice" }

// With expressions
const prefix = "user";
const obj = {
  [`${prefix}Name`]: "Bob",
  [`${prefix}Age`]: 30
};
console.log(obj);  // { userName: "Bob", userAge: 30 }

Shorthand Property Names

If variable name matches property name:

const name = "Alice";
const age = 25;

// Old way: repeat the variable name as the key
const personVerbose = {
  name: name,
  age: age
};
console.log(personVerbose);  // { name: "Alice", age: 25 }

When the key and variable share a name, shorthand does the same thing:

const name = "Alice";
const age = 25;

const person = { name, age };
console.log(person);  // { name: "Alice", age: 25 }

Common Patterns

Merge caller options over a set of defaults:

function createUser(options) {
  const defaults = {
    role: "user",
    active: true
  };

  return { ...defaults, ...options };
}

const admin = createUser({ name: "Alice", role: "admin" });
console.log(admin);
// { role: "admin", active: true, name: "Alice" }

Transform every value in an object with entries and fromEntries:

const prices = { apple: 1, banana: 2, orange: 3 };

const doubled = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 2])
);
console.log(doubled);
// { apple: 2, banana: 4, orange: 6 }

Filter out properties you don't want to expose:

const user = {
  name: "Alice",
  password: "secret",
  email: "[email protected]"
};

const safe = Object.fromEntries(
  Object.entries(user).filter(([key]) => key !== "password")
);
console.log(safe);
// { name: "Alice", email: "[email protected]" }

Key Takeaways

  • Objects store key-value pairs, accessed with dot notation or bracket notation for dynamic keys
  • Methods are functions stored as object properties, use regular functions (not arrows) to access this
  • Spread operator (...) copies and merges objects
  • Destructuring extracts properties into variables, supports renaming and defaults
  • Object.keys(), Object.values(), Object.entries() help iterate over objects
  • for...in loops over keys, for...of loops over values (use with Object.entries() for objects)
  • Check if a property exists with "key" in obj or hasOwnProperty()
  • Optional chaining (?.) safely accesses nested properties without errors
  • Properties can be added, modified, or removed (delete) at any time
  • Shorthand syntax: { name } instead of { name: name } when variable matches key

🎁 So far your code changes what's already on the page. But how does JavaScript actually reach into the HTML to create, update, and delete elements on the fly?

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

Spot something off? Report an issue
© 2026 ByteLearn.dev. Free courses for developers. · Privacy