Understanding Object-Oriented Programming in JavaScript
As your programs grow, you'll find yourself creating many objects that share the same structure like multiple users, multiple products, multiple students. Typing out each one manually doesn't scale. There has to be a better way.
That better way is Object-Oriented Programming.
What Is OOP?
Object-Oriented Programming (OOP) is a style of writing code that organizes everything around objects , bundles of related data and behavior.
Instead of writing separate variables and functions scattered across your code, OOP lets you define a template once and create as many objects from it as you need. Each object gets its own data but shares the same structure and behavior.
The core idea: model your code the way you'd model the real world.
The Blueprint Analogy
Think about a car factory. An architect designs a blueprint , it specifies that every car will have a brand, a model, a color, and the ability to start and stop. The blueprint itself isn't a car. But you can use it to manufacture as many cars as you want, each with their own specific details.
In JavaScript:
The blueprint is a class
Each car manufactured from it is an instance (an object)
What Is a Class?
A class is a template for creating objects. It defines what properties an object will have and what actions it can perform.
class Car {
// properties and methods go here
}
That's the shell. Now let's fill it in.
The Constructor Method
The constructor is a special method inside a class that runs automatically whenever you create a new object from it. It's where you set up the initial properties.
class Car {
constructor(brand, model, color) {
this.brand = brand;
this.model = model;
this.color = color;
}
}
this refers to the specific object being created. When you make a red Toyota, this.color becomes "red" for that object. When you make a blue Honda, this.color becomes "blue" for that one.
Creating objects from a class
Use the new keyword to create an instance:
const car1 = new Car("Toyota", "Camry", "Red");
const car2 = new Car("Honda", "Civic", "Blue");
const car3 = new Car("Ford", "Mustang", "Black");
console.log(car1.brand); // "Toyota"
console.log(car2.color); // "Blue"
console.log(car3.model); // "Mustang"
Three objects, one class, no repeated structure. That's the reusability OOP gives you.
Methods Inside a Class
A method is a function that belongs to a class โ it defines what an object can do.
class Car {
constructor(brand, model, color) {
this.brand = brand;
this.model = model;
this.color = color;
}
describe() {
return this.color + " " + this.brand + " " + this.model;
}
start() {
return this.brand + " is starting... ๐";
}
}
const car1 = new Car("Toyota", "Camry", "Red");
const car2 = new Car("Honda", "Civic", "Blue");
console.log(car1.describe()); // "Red Toyota Camry"
console.log(car2.start()); // "Honda is starting... ๐"
Every object created from Car automatically gets describe() and start(). You define the method once and all instances share it.
A Person Example
Let's try a cleaner, more relatable example:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return "Hi, I'm " + this.name + " and I'm " + this.age + " years old.";
}
isAdult() {
return this.age >= 18;
}
}
const alice = new Person("Alice", 25);
const bob = new Person("Bob", 16);
console.log(alice.greet()); // "Hi, I'm Alice and I'm 25 years old."
console.log(bob.greet()); // "Hi, I'm Bob and I'm 16 years old."
console.log(alice.isAdult()); // true
console.log(bob.isAdult()); // false
Each Person object has its own name and age, but they both share the same greet() and isAdult() behavior defined in the class.
Class vs Manually Creating Objects
To appreciate why classes matter, look at what life looks like without them:
// Without a class โ creating 3 students manually ๐ซ
const student1 = { name: "Riya", age: 20, course: "CS" };
const student2 = { name: "Arjun", age: 21, course: "Math" };
const student3 = { name: "Priya", age: 19, course: "Physics" };
// You'd have to write a separate function for each...
function getDetails(student) {
return student.name + " | " + student.age + " | " + student.course;
}
// With a class โ one template, infinite objects โ
class Student {
constructor(name, age, course) {
this.name = name;
this.age = age;
this.course = course;
}
getDetails() {
return this.name + " | " + this.age + " | " + this.course;
}
}
const s1 = new Student("Riya", 20, "CS");
const s2 = new Student("Arjun", 21, "Math");
const s3 = new Student("Priya", 19, "Physics");
console.log(s1.getDetails()); // "Riya | 20 | CS"
console.log(s2.getDetails()); // "Arjun | 21 | Math"
console.log(s3.getDetails()); // "Priya | 19 | Physics"
The structure is defined once. Adding a fourth or fortieth student takes one line.
The Idea of Encapsulation
Encapsulation means keeping related data and behavior bundled together and ideally, keeping the internal details of an object private so the outside world only interacts with it through defined methods.
In simple terms: an object should manage its own data.
class BankAccount {
constructor(owner, balance) {
this.owner = owner;
this.balance = balance;
}
deposit(amount) {
this.balance += amount;
return "Deposited โน" + amount + ". New balance: โน" + this.balance;
}
withdraw(amount) {
if (amount > this.balance) {
return "Insufficient funds.";
}
this.balance -= amount;
return "Withdrawn โน" + amount + ". New balance: โน" + this.balance;
}
getBalance() {
return "Balance: โน" + this.balance;
}
}
const account = new BankAccount("Alice", 1000);
console.log(account.deposit(500)); // "Deposited โน500. New balance: โน1500"
console.log(account.withdraw(200)); // "Withdrawn โน200. New balance: โน1300"
console.log(account.withdraw(2000)); // "Insufficient funds."
console.log(account.getBalance()); // "Balance: โน1300"
Notice that you don't directly set account.balance = 9999. Instead, you go through deposit() and withdraw(), which contain logic to keep the data valid. The object controls its own state and that's encapsulation.
Class โ Instance at a Glance
Quick Reference
// Define a class
class ClassName {
constructor(param1, param2) {
this.property1 = param1;
this.property2 = param2;
}
methodName() {
return this.property1; // use this to access own data
}
}
// Create instances
const obj1 = new ClassName("value1", "value2");
const obj2 = new ClassName("other1", "other2");
// Use them
obj1.methodName();
obj2.property1;
Wrapping Up
OOP is one of the most important shifts in thinking when you move from beginner to intermediate JavaScript. You're no longer just writing a list of instructions but you're modeling the world in code.
Here's what to carry forward:
A class is a blueprint โ it defines the shape and behavior of objects
The constructor runs when you create a new object and sets up its initial data
thisrefers to the specific instance being created or usedMethods are functions inside a class โ they define what an object can do
Use
newto create instances from a classEncapsulation means keeping data and the logic that manages it together in one object
Classes shine when you need multiple objects with the same structure โ write once, use everywhere
Try building a Student class, create a few instances, and call a method on each. Once it clicks, you'll see OOP patterns everywhere. ๐