JavaScript Objects

Objects are one of the most important data types in JavaScript. They allow you to store collections of related data and functionality together using key-value pairs.

Try It Yourself

Experiment with creating and manipulating objects:

index.js
// JavaScript Objects - try modifying this code!

// Creating an object
const person = {
  name: "Alice",
  age: 28,
  city: "New York",
  hobbies: ["reading", "coding", "hiking"],
  greet: function() {
    return "Hello, I'm " + this.name + "!";
  }
};

// Accessing properties
console.log("Name:", person.name);
console.log("Age:", person["age"]);
console.log("First hobby:", person.hobbies[0]);

// Calling a method
console.log(person.greet());

// Modifying properties
person.age = 29;
person.country = "USA"; // Adding new property

console.log("\nUpdated object:");
console.log(person);

// Object methods
console.log("\nKeys:", Object.keys(person));
console.log("Values:", Object.values(person));

Creating Objects

The most common way to create an object is using object literal syntax with curly braces:

javascript
// Object literal syntax - most common way
const person = {
  firstName: "John",
  lastName: "Doe",
  age: 30,
  isEmployed: true
};

// Empty object
const emptyObj = {};

// Object with various value types
const mixed = {
  text: "Hello",           // String
  number: 42,              // Number
  active: true,            // Boolean
  nothing: null,           // Null
  items: [1, 2, 3],        // Array
  nested: { a: 1, b: 2 },  // Nested object
  greet: function() {      // Function (method)
    return "Hi!";
  }
};
Objects are Reference Types
Unlike primitive values, objects are stored by reference. When you assign an object to a variable, you're storing a reference to the object, not a copy.

Accessing Properties

You can access object properties using dot notation or bracket notation:

javascript
const car = {
  brand: "Toyota",
  model: "Camry",
  year: 2023,
  "fuel type": "Hybrid" // Key with space
};

// Dot notation - clean and common
console.log(car.brand);    // "Toyota"
console.log(car.model);    // "Camry"

// Bracket notation - flexible
console.log(car["year"]);       // 2023
console.log(car["fuel type"]);  // "Hybrid" (required for spaces)

// Dynamic property access
const prop = "brand";
console.log(car[prop]);    // "Toyota" (using variable)

// Accessing undefined property
console.log(car.color);    // undefined (no error)
FeatureDot NotationBracket Notation
Syntaxobj.propertyobj["property"]
Dynamic keys
Spaces in keys
Special characters
ReadabilityBetterGood
Use caseKnown property namesVariable/computed names

Modifying Objects

Objects are mutable - you can add, update, and delete properties:

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

// Updating existing properties
user.age = 26;
user["name"] = "Alice Smith";

// Adding new properties
user.email = "alice@example.com";
user["phone"] = "555-1234";

// Deleting properties
delete user.phone;

console.log(user);
// { name: "Alice Smith", age: 26, email: "alice@example.com" }

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

ES6 Shorthand Syntax

ES6 introduced cleaner ways to define object properties and methods:

javascript
// Property shorthand (ES6)
const name = "Bob";
const age = 30;

// Old way
const person1 = { name: name, age: age };

// Shorthand - when variable name matches property name
const person2 = { name, age };
console.log(person2); // { name: "Bob", age: 30 }

// Method shorthand (ES6)
const calculator = {
  // Old way
  add: function(a, b) {
    return a + b;
  },

  // Shorthand
  subtract(a, b) {
    return a - b;
  }
};

// Computed property names (ES6)
const propName = "score";
const game = {
  [propName]: 100,
  ["player" + 1]: "Alice"
};
console.log(game); // { score: 100, player1: "Alice" }

Nested Objects

Objects can contain other objects, creating nested structures:

javascript
const company = {
  name: "TechCorp",
  address: {
    street: "123 Main St",
    city: "San Francisco",
    country: "USA"
  },
  employees: [
    { name: "Alice", role: "Developer" },
    { name: "Bob", role: "Designer" }
  ]
};

// Accessing nested properties
console.log(company.address.city);        // "San Francisco"
console.log(company.employees[0].name);   // "Alice"

// Safe access with optional chaining (?.)
console.log(company.address?.zipCode);    // undefined (no error)
console.log(company.ceo?.name);           // undefined (no error)

// Modifying nested properties
company.address.zipCode = "94102";
company.employees.push({ name: "Carol", role: "Manager" });
Optional Chaining (?.)
Use optional chaining to safely access nested properties without checking each level for null/undefined. It returns undefined instead of throwing an error.

Iterating Over Objects

There are several ways to loop through an object's properties:

javascript
const product = {
  name: "Laptop",
  price: 999,
  inStock: true
};

// for...in loop
console.log("--- for...in ---");
for (const key in product) {
  console.log(key + ": " + product[key]);
}

// Object.keys() - array of keys
console.log("\nKeys:", Object.keys(product));
// ["name", "price", "inStock"]

// Object.values() - array of values
console.log("Values:", Object.values(product));
// ["Laptop", 999, true]

// Object.entries() - array of [key, value] pairs
console.log("Entries:", Object.entries(product));
// [["name", "Laptop"], ["price", 999], ["inStock", true]]

// Iterating with forEach
Object.entries(product).forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});

Object Destructuring

Destructuring allows you to extract properties into variables with a concise syntax:

javascript
const person = {
  name: "Alice",
  age: 28,
  city: "NYC",
  country: "USA"
};

// Basic destructuring
const { name, age } = person;
console.log(name); // "Alice"
console.log(age);  // 28

// Renaming variables
const { city: location } = person;
console.log(location); // "NYC"

// Default values
const { phone = "N/A" } = person;
console.log(phone); // "N/A"

// Rest operator
const { name: userName, ...rest } = person;
console.log(userName); // "Alice"
console.log(rest);     // { age: 28, city: "NYC", country: "USA" }

// Nested destructuring
const company = {
  info: { name: "TechCorp", founded: 2020 }
};
const { info: { name: companyName } } = company;
console.log(companyName); // "TechCorp"

Spread Operator

The spread operator (...) is useful for copying and merging objects:

javascript
// Copying objects (shallow copy)
const original = { a: 1, b: 2 };
const copy = { ...original };
console.log(copy); // { a: 1, b: 2 }

// Merging objects
const defaults = { theme: "dark", lang: "en" };
const userPrefs = { theme: "light" };
const settings = { ...defaults, ...userPrefs };
console.log(settings); // { theme: "light", lang: "en" }

// Adding/overriding properties
const user = { name: "Alice", age: 25 };
const updatedUser = { ...user, age: 26, city: "NYC" };
console.log(updatedUser);
// { name: "Alice", age: 26, city: "NYC" }

// Note: Spread creates a SHALLOW copy
const nested = { a: { b: 1 } };
const shallowCopy = { ...nested };
shallowCopy.a.b = 99;
console.log(nested.a.b); // 99 (original also changed!)
Shallow Copy Warning
The spread operator creates a shallow copy. Nested objects are still referenced, not duplicated. Modifying nested objects in the copy will affect the original.

Built-in Object Methods

JavaScript provides many useful static methods on the Object constructor:

javascript
const obj = { a: 1, b: 2, c: 3 };

// Object.keys() - get all keys
console.log(Object.keys(obj)); // ["a", "b", "c"]

// Object.values() - get all values
console.log(Object.values(obj)); // [1, 2, 3]

// Object.entries() - get [key, value] pairs
console.log(Object.entries(obj)); // [["a", 1], ["b", 2], ["c", 3]]

// Object.assign() - copy/merge objects
const target = { x: 1 };
const source = { y: 2 };
Object.assign(target, source);
console.log(target); // { x: 1, y: 2 }

// Object.freeze() - prevent modifications
const frozen = Object.freeze({ name: "Alice" });
frozen.name = "Bob";    // Silently fails (or error in strict mode)
console.log(frozen.name); // "Alice"

// Object.seal() - prevent adding/removing (but can modify)
const sealed = Object.seal({ name: "Alice" });
sealed.name = "Bob";    // Works
sealed.age = 25;        // Fails
console.log(sealed);    // { name: "Bob" }

// Object.fromEntries() - create object from entries
const entries = [["a", 1], ["b", 2]];
console.log(Object.fromEntries(entries)); // { a: 1, b: 2 }

Test Your Knowledge

JavaScript Objects Quiz

5 questions
Question 1

How do you access a property with a space in its name?

Question 2

What does Object.keys(obj) return?

Question 3

What is the output of: const { a = 5 } = { b: 10 }; console.log(a);

Question 4

What does the spread operator (...) do with objects?

Question 5

How do you check if an object has a specific property?

Coding Challenge

Deep Merge Objects
Hard

Create a function that deeply merges two objects. Unlike the spread operator which only does a shallow merge, your function should recursively merge nested objects.

Starter Code
// Challenge: Create a function that merges two objects deeply
// Unlike spread (...) which does shallow merge, this should merge nested objects

function deepMerge(target, source) {
  // Your code here
  // Hint: Check if values are objects, then recursively merge
}

// Test cases
const obj1 = {
  name: "Product",
  details: {
    price: 100,
    stock: 50
  },
  tags: ["sale"]
};

const obj2 = {
  details: {
    price: 80,
    discount: true
  },
  tags: ["featured"],
  active: true
};

const result = deepMerge(obj1, obj2);
console.log(result);
// Expected:
// {
//   name: "Product",
//   details: { price: 80, stock: 50, discount: true },
//   tags: ["featured"],
//   active: true
// }

Summary

  • Objects store data as key-value pairs using curly braces {}
  • Access properties with dot notation (obj.key) or bracket notation (obj["key"])
  • Objects are mutable - you can add, update, and delete properties
  • Destructuring extracts properties into variables: const {'{'} name {'}'} = obj
  • The spread operator (...) copies and merges objects (shallow copy)
  • Use Object.keys(), Object.values(), and Object.entries() to iterate over objects
  • Optional chaining (?.) safely accesses nested properties