# Understanding Object-Oriented Programming in JavaScript

You use a smartphone every day. You know that every contact in your phone has a **name**, a **number**, maybe a **photo**. Each contact looks the same *structurally* but they all have *different data*.

That right there? That's Object-Oriented Programming. You've been living it. Now let's actually understand it

**What Even IS Object-Oriented Programming?**

OOP (Object-Oriented Programming) is just a **way of organizing your code** so it's clean, reusable, and actually makes sense when you come back to it 3 months later at 2am panicking.

Instead of writing the same code over and over, you create a **template** and then use that template to stamp out as many copies as you need.

What is a Class in JavaScript?

A **class** is like a factory blueprint. It defines:

*   What **properties** (data) an object will have
    
*   What **actions** (methods) the object can perform
    

**The Constructor**

When you create a new object from a class, JavaScript automatically runs a special method called `constructor`

**Creating Objects From a Class**

Now let's actually **build some cars** from that blueprint using the `new` keyword:

````javascript
class Car {
  constructor(color, speed) {
    this.color = color;
    this.speed = speed;
  }
}

// Creating objects (instances)
const myCar  = new Car("red",   120);
const hisCar = new Car("blue",  180);
const herCar = new Car("black", 200);

console.log(myCar.color);   // "red"
console.log(hisCar.speed);  // 180
console.log(herCar.color);  // "black"
```

Each time you write `new Car(...)`, JavaScript:
1. Creates a fresh, empty object
2. Runs the `constructor` with whatever values you passed
3. Hands you back a fully set-up object
```
new Car("red", 120)
        │
        ▼
  constructor runs
  ┌─────────────────┐
  │ this.color = "red"  │
  │ this.speed = 120    │
  └─────────────────┘
        │
        ▼
  Returns → myCar object ✅
````

Three cars. **Zero repeated code.** That's reusability doing its thing.

**Methods — Giving Your Objects Superpowers**

Properties store *data*. Methods are *actions* the object can perform. You define them right inside the class:

```javascript
class Car {
  constructor(color, speed) {
    this.color = color;
    this.speed = speed;
  }

  // METHOD: an action the car can perform
  drive() {
    console.log(`The ${this.color} car is driving at ${this.speed} km/h!`);
  }

  honk() {
    console.log("Beep beep! 📯");
  }
}

const myCar = new Car("red", 120);
myCar.drive();  // "The red car is driving at 120 km/h!"
myCar.honk();   // "Beep beep! 📯"

const hisCar = new Car("blue", 180);
hisCar.drive(); // "The blue car is driving at 180 km/h!"
```

Notice how `myCar.drive()` and `hisCar.drive()` print **different things** even though they use the **same method**. That's because `this.color` refers to each object's own color.

**Encapsulation**

Encapsulation sounds fancy. It just means: **keep related stuff together, and hide what doesn't need to be public.**

Imagine your phone. You press the volume button you don't need to know how the speaker firmware works internally. The complexity is **hidden**. You just get a simple interface.

In code, encapsulation means bundling your data (properties) and behavior (methods) inside the class, so the outside world only sees what it needs to:

```javascript
class BankAccount {
  constructor(owner, balance) {
    this.owner = owner;
    this._balance = balance; // _ means "treat this as private, don't touch directly"
  }

  deposit(amount) {
    this._balance += amount;
    console.log(`Deposited $${amount}. New balance: $${this._balance}`);
  }

  getBalance() {
    return this._balance; // controlled access — you can see it, but through me
  }
}

const myAccount = new BankAccount("Alex", 1000);
myAccount.deposit(500);          // Deposited $500. New balance: $1500
console.log(myAccount.getBalance()); // 1500

// You CAN'T (shouldn't) do this:
// myAccount._balance = 999999; ← bad practice, bypasses all logic
```

**Putting It All Together — The Person Class**

Let's build one clean example that shows everything:

```javascript
class Person {
  constructor(name, age) {
    this.name = name;
    this.age  = age;
  }

  greet() {
    console.log(`Hey! I'm ${this.name} and I'm ${this.age} years old.`);
  }

  haveBirthday() {
    this.age++;
    console.log(`Happy Birthday ${this.name}! You're now ${this.age}! 🎂`);
  }
}

const alice = new Person("Alice", 22);
const bob   = new Person("Bob",   19);

alice.greet();         // Hey! I'm Alice and I'm 22 years old.
bob.greet();           // Hey! I'm Bob and I'm 19 years old.

alice.haveBirthday();  // Happy Birthday Alice! You're now 23! 🎂
alice.greet();         // Hey! I'm Alice and I'm 23 years old.

// bob is completely unaffected ✅
bob.greet();           // Hey! I'm Bob and I'm 19 years old.
```

One class → unlimited unique objects. Write once, use forever.

**Assignment**

Build a `Student` class from scratch:

```javascript
class Student {
  constructor(name, age) {
    this.name = name;
    this.age  = age;
  }

  printDetails() {
    console.log(`Student: ${this.name}, Age: ${this.age}`);
  }
}

// Now create 3 different students
const s1 = new Student("Priya",  20);
const s2 = new Student("Jordan", 22);
const s3 = new Student("Mei",    19);

s1.printDetails(); // Student: Priya, Age: 20
s2.printDetails(); // Student: Jordan, Age: 22
s3.printDetails(); // Student: Mei, Age: 19
```

**Once you've got that working, try adding:**

*   A `grade` property (like "A", "B", "C")
    
*   A `study()` method that prints `"${this.name} is studying hard! 📚"`
    
*   A `pass()` method that checks if grade is "A" or "B" and prints whether they passed
