Labs ICT
โญ Pro Login

OO Concepts

Understanding Classes, Objects, Encapsulation, and the core building blocks of OO.

Objects and Classes

A class is a blueprint or template that defines what an object looks like and what it can do. An object is a concrete instance of that class โ€” a real thing in memory with actual values. Think of a class as a cookie cutter and objects as the cookies it produces.

Every class has two main components: attributes (data that describes the object) and operations (methods that define what the object can do). Together, they encapsulate the object's state and behavior in one place.

// Class = Blueprint
class Car {
  // Attributes (what it knows)
  constructor(make, model, year, color) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.color = color;
    this.speed = 0;
    this.engineRunning = false;
  }

  // Operations (what it does)
  start() {
    this.engineRunning = true;
    console.log(`${this.make} ${this.model} started.`);
  }

  accelerate(amount) {
    if (!this.engineRunning) {
      console.log("Start the engine first!");
      return;
    }
    this.speed += amount;
    console.log(`Speed: ${this.speed} km/h`);
  }

  brake(amount) {
    this.speed = Math.max(0, this.speed - amount);
    console.log(`Speed: ${this.speed} km/h`);
  }
}

// Objects = Instances of the class
const myCar = new Car("Toyota", "Corolla", 2024, "Silver");
const yourCar = new Car("Honda", "Civic", 2023, "Blue");

myCar.start();           // Toyota Corolla started.
myCar.accelerate(60);    // Speed: 60 km/h
myCar.brake(20);         // Speed: 40 km/h

console.log(myCar.make);   // Toyota
console.log(yourCar.color); // Blue

Encapsulation

Encapsulation is the bundling of data (attributes) and the methods that operate on that data into a single unit (the class), while restricting direct access to some components. It's like a capsule that holds medicine โ€” the inside is protected, and you interact with it through a controlled interface.

The key mechanism is access control. By marking attributes as private and providing public methods to access them, you control how external code interacts with the object. This prevents invalid states and makes code easier to maintain.

class BankAccount {
  // Private attributes โ€” cannot be accessed directly from outside
  #balance;
  #owner;

  constructor(owner, initialBalance) {
    this.#owner = owner;
    this.#balance = initialBalance;
  }

  // Public interface โ€” controlled access
  deposit(amount) {
    if (amount <= 0) {
      console.log("Deposit amount must be positive.");
      return;
    }
    this.#balance += amount;
    console.log(`Deposited $${amount}. Balance: $${this.#balance}`);
  }

  withdraw(amount) {
    if (amount <= 0) {
      console.log("Withdrawal amount must be positive.");
      return;
    }
    if (amount > this.#balance) {
      console.log("Insufficient funds!");
      return;
    }
    this.#balance -= amount;
    console.log(`Withdrew $${amount}. Balance: $${this.#balance}`);
  }

  getBalance() {
    return this.#balance;
  }

  getOwner() {
    return this.#owner;
  }
}

const account = new BankAccount("Alice", 1000);
account.deposit(500);        // Deposited $500. Balance: $1500
account.withdraw(200);       // Withdrew $200. Balance: $1300
console.log(account.getBalance()); // 1300
// account.#balance = 999999;     โ† Would cause an error!

Why Encapsulation Matters

Without encapsulation, any code could modify an object's internal state in unpredictable ways. You'd have no guarantee that a BankAccount's balance is always valid, or that a Car's speed is never negative. Encapsulation gives you control โ€” you validate inputs, maintain invariants, and keep objects in a consistent state.

It also creates a clean interface between objects. Users of a class don't need to know how it works internally โ€” they just call methods. If you later change the internal implementation (say, switching from a number to a currency object for balance), nothing breaks as long as the public interface stays the same.

Identity, State, and Behavior

Every object has three characteristics: identity (a unique reference, even if two objects have the same data), state (the current values of its attributes), and behavior (what it can do through its methods).

class Temperature {
  constructor(celsius) {
    this.celsius = celsius; // state
  }

  // behavior
  toFahrenheit() {
    return this.celsius * 9 / 5 + 32;
  }

  toKelvin() {
    return this.celsius + 273.15;
  }

  describe() {
    return `${this.celsius}ยฐC = ${this.toFahrenheit()}ยฐF = ${this.toKelvin()}K`;
  }
}

const freezing = new Temperature(0);
const bodyTemp = new Temperature(37);

// Identity: freezing and bodyTemp are different objects
console.log(freezing === bodyTemp); // false

// State: each has its own data
console.log(freezing.celsius); // 0
console.log(bodyTemp.celsius); // 37

// Behavior: each can perform operations
console.log(freezing.describe());  // 0ยฐC = 32ยฐF = 273.15K
console.log(bodyTemp.describe());  // 37ยฐC = 98.6ยฐF = 310.15K

๐Ÿงช Quick Quiz

What is an object in OO programming?