Lesson 34: Creating Objects Part 2

Master advanced JavaScript object techniques - learn about prototypes, classes, inheritance, and modern object patterns with interactive examples.

34.1 Prototypes and Inheritance

JavaScript uses prototypes for inheritance. Every object has a prototype object from which it inherits properties and methods.

Key concepts:
  • All JavaScript objects inherit properties from a prototype
  • Constructor functions have a prototype property
  • Objects created with a constructor inherit from the constructor's prototype
  • The prototype chain allows for inheritance and method sharing
  • Object.create() creates a new object with a specified prototype
// Constructor function
function Animal(name) {
  this.name = name;
}

// Add method to prototype
Animal.prototype.speak = function() {
  return `${this.name} makes a sound.`;
};

// Create an instance
const dog = new Animal('Dog');
console.log(dog.speak()); // Dog makes a sound.

// Inheritance using prototype
function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

// Set up prototype chain
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// Add method to Dog prototype
Dog.prototype.bark = function() {
  return `${this.name} barks!`;
};

const labrador = new Dog('Max', 'Labrador');
console.log(labrador.speak()); // Max makes a sound.
console.log(labrador.bark()); // Max barks!

Example 34.1: Prototype Chain Explorer

Visualize the prototype chain of objects:

labrador Instance
name: "Max"
breed: "Labrador"
Dog.prototype
constructor: Dog
bark: function()
Animal.prototype
constructor: Animal
speak: function()
Object.prototype
toString: function()
hasOwnProperty: function()

34.2 Classes in JavaScript (ES6)

ES6 introduced the class syntax, which provides a cleaner way to create objects and handle inheritance.

// Class declaration
class Vehicle {
  constructor(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
  }
  
  // Method
  getInfo() {
    return `${this.year} ${this.make} ${this.model}`;
  }
  
  // Static method
  static getVehicleType() {
    return 'Generic Vehicle';
  }
}

// Create an instance
const car = new Vehicle('Toyota', 'Camry', 2020);
console.log(car.getInfo()); // 2020 Toyota Camry

// Inheritance with classes
class Car extends Vehicle {
  constructor(make, model, year, doors) {
    super(make, model, year); // Call parent constructor
    this.doors = doors;
  }
  
  // Override method
  getInfo() {
    return `${super.getInfo()} with ${this.doors} doors`;
  }
}

const sedan = new Car('Honda', 'Accord', 2021, 4);
console.log(sedan.getInfo()); // 2021 Honda Accord with 4 doors
console.log(Car.getVehicleType()); // Generic Vehicle

Example 34.2: Class Explorer

Create and interact with class instances:

34.3 Getters and Setters

Getters and setters allow you to define object accessors for computed properties.

class Circle {
  constructor(radius) {
    this.radius = radius;
  }
  
  // Getter
  get diameter() {
    return this.radius * 2;
  }
  
  // Setter
  set diameter(value) {
    this.radius = value / 2;
  }
  
  // Getter for area
  get area() {
    return Math.PI * this.radius ** 2;
  }
}

const myCircle = new Circle(5);
console.log(myCircle.diameter); // 10 (getter)
myCircle.diameter = 14; // Setter
console.log(myCircle.radius); // 7
console.log(myCircle.area.toFixed(2)); // 153.94

Example 34.3: Circle Calculator

Use getters and setters to calculate circle properties:

34.4 Object Composition

Object composition is an alternative to classical inheritance where objects are combined to create more complex objects.

// Basic behaviors
const canEat = {
  eat: function() {
    return `${this.name} is eating.`;
  }
};

const canSleep = {
  sleep: function() {
    return `${this.name} is sleeping.`;
  }
};

const canCode = {
  code: function() {
    return `${this.name} is coding JavaScript.`;
  }
};

// Composed object
function createDeveloper(name) {
  const developer = { name };
  return Object.assign(developer, canEat, canSleep, canCode);
}

const john = createDeveloper('John');
console.log(john.eat()); // John is eating.
console.log(john.code()); // John is coding JavaScript.

Example 34.4: Object Composition Explorer

Combine behaviors to create different objects:

34.5 Object Destructuring

Destructuring allows you to extract values from objects into distinct variables.

const person = {
  firstName: 'John',
  lastName: 'Doe',
  age: 30,
  address: {
    city: 'New York',
    country: 'USA'
  }
};

// Basic destructuring
const { firstName, lastName } = person;
console.log(firstName, lastName); // John Doe

// Destructuring with renaming
const { firstName: fName, lastName: lName } = person;
console.log(fName, lName); // John Doe

// Nested destructuring
const { address: { city, country } } = person;
console.log(city, country); // New York USA

// Function parameter destructuring
function displayPerson({ firstName, age }) {
  return `${firstName} is ${age} years old`;
}
console.log(displayPerson(person)); // John is 30 years old

Example 34.5: Destructuring Practice

Practice extracting values with destructuring: