JavaScript Classes and Object-Oriented Programming
Object-Oriented Programming (OOP) is a way of organizing code around objects — entities that combine data (properties) and behavior (methods). JavaScript classes, introduced in ES6, provide a clean and readable syntax for creating objects using the OOP approach.
Real-life analogy: A class is like a blueprint for a house. Multiple houses can be built from the same blueprint, each with its own address and color, but all sharing the same structure and rooms.
What is a Class?
A class is a template (blueprint) for creating objects. Once a class is defined, multiple objects (called instances) can be created from it, each with their own data.
Defining a Class
class Animal {
constructor(name, sound) {
this.name = name;
this.sound = sound;
}
speak() {
console.log(`${this.name} says ${this.sound}!`);
}
}
let dog = new Animal("Dog", "Woof");
let cat = new Animal("Cat", "Meow");
dog.speak(); // Dog says Woof!
cat.speak(); // Cat says Meow!Key Parts of a Class
| Part | Description |
|---|---|
| class keyword | Declares the class |
| constructor() | Special method that runs automatically when a new object is created |
| this | Refers to the current object being created |
| Methods | Functions defined inside the class that describe behavior |
| new keyword | Creates a new instance (object) from the class |
The constructor Method
The constructor is automatically called when new ClassName() is used. It sets up the initial state of the object.
class Student {
constructor(name, age, grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
introduce() {
console.log(`Hi, I am ${this.name}, age ${this.age}, in Grade ${this.grade}.`);
}
}
let s1 = new Student("Riya", 16, 10);
let s2 = new Student("Arjun", 17, 11);
s1.introduce(); // Hi, I am Riya, age 16, in Grade 10.
s2.introduce(); // Hi, I am Arjun, age 17, in Grade 11.Class Methods
Methods are functions defined inside a class. They describe what an object can do.
class BankAccount {
constructor(owner, balance) {
this.owner = owner;
this.balance = balance;
}
deposit(amount) {
this.balance += amount;
console.log(`Deposited ₹${amount}. New balance: ₹${this.balance}`);
}
withdraw(amount) {
if (amount > this.balance) {
console.log("Insufficient funds.");
} else {
this.balance -= amount;
console.log(`Withdrawn ₹${amount}. Remaining: ₹${this.balance}`);
}
}
showBalance() {
console.log(`${this.owner}'s balance: ₹${this.balance}`);
}
}
let account = new BankAccount("Neha", 5000);
account.deposit(1000); // Deposited ₹1000. New balance: ₹6000
account.withdraw(2500); // Withdrawn ₹2500. Remaining: ₹3500
account.showBalance(); // Neha's balance: ₹3500Getters and Setters
Getters and setters allow controlled access to object properties. A getter reads a value; a setter validates and sets a value.
class Temperature {
constructor(celsius) {
this._celsius = celsius;
}
get fahrenheit() {
return (this._celsius * 9 / 5) + 32;
}
set celsius(value) {
if (value < -273.15) {
console.log("Temperature below absolute zero is not valid.");
} else {
this._celsius = value;
}
}
get celsius() {
return this._celsius;
}
}
let temp = new Temperature(100);
console.log(temp.fahrenheit); // 212
temp.celsius = 37;
console.log(temp.celsius); // 37
console.log(temp.fahrenheit); // 98.6Static Methods
Static methods belong to the class itself — not to individual instances. They are called directly on the class name.
class MathHelper {
static square(n) {
return n * n;
}
static cube(n) {
return n * n * n;
}
static isEven(n) {
return n % 2 === 0;
}
}
console.log(MathHelper.square(5)); // 25
console.log(MathHelper.cube(3)); // 27
console.log(MathHelper.isEven(8)); // true
// Static methods cannot be called on an instance:
// let m = new MathHelper();
// m.square(4); // TypeErrorInheritance — Extending a Class
Inheritance allows one class to extend another, reusing its properties and methods while adding or overriding specific behavior. The extends keyword creates the parent-child relationship.
class Vehicle {
constructor(brand, speed) {
this.brand = brand;
this.speed = speed;
}
move() {
console.log(`${this.brand} is moving at ${this.speed} km/h.`);
}
}
class Car extends Vehicle {
constructor(brand, speed, doors) {
super(brand, speed); // Call parent constructor
this.doors = doors;
}
describe() {
console.log(`${this.brand} car with ${this.doors} doors, speed ${this.speed} km/h.`);
}
}
let myCar = new Car("Toyota", 120, 4);
myCar.move(); // Toyota is moving at 120 km/h.
myCar.describe(); // Toyota car with 4 doors, speed 120 km/h.The super Keyword
super() calls the parent class constructor. It must be called before using this in a child constructor.
Method Overriding
A child class can override a method from the parent class to provide different behavior.
class Shape {
area() {
return 0;
}
describe() {
console.log(`Area: ${this.area()}`);
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
area() {
return (Math.PI * this.radius * this.radius).toFixed(2);
}
}
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
let c = new Circle(7);
let r = new Rectangle(4, 6);
c.describe(); // Area: 153.94
r.describe(); // Area: 24instanceof — Check Object Type
let c = new Circle(5);
console.log(c instanceof Circle); // true
console.log(c instanceof Shape); // true (inherits from Shape)
console.log(c instanceof Array); // falsePrivate Fields (ES2022)
Private fields use the # prefix and cannot be accessed from outside the class.
class User {
#password;
constructor(username, password) {
this.username = username;
this.#password = password;
}
checkPassword(input) {
return input === this.#password;
}
}
let user = new User("admin", "secret123");
console.log(user.username); // admin
console.log(user.checkPassword("secret123")); // true
// console.log(user.#password); // SyntaxError — private!Four Pillars of OOP
| Pillar | Meaning | JavaScript Feature |
|---|---|---|
| Encapsulation | Bundle data and methods together, hide internal details | Classes, private fields (#) |
| Abstraction | Show only what is necessary, hide complexity | Methods, getters/setters |
| Inheritance | Child class reuses parent class features | extends, super |
| Polymorphism | Same method name behaves differently in different classes | Method overriding |
Practical Example — Library System
class Book {
#checkedOut = false;
constructor(title, author) {
this.title = title;
this.author = author;
}
checkout() {
if (this.#checkedOut) {
console.log(`"${this.title}" is already checked out.`);
} else {
this.#checkedOut = true;
console.log(`"${this.title}" checked out successfully.`);
}
}
returnBook() {
this.#checkedOut = false;
console.log(`"${this.title}" returned. Thank you!`);
}
get status() {
return this.#checkedOut ? "Checked Out" : "Available";
}
}
let book1 = new Book("JavaScript Mastery", "Rohan Shah");
console.log(book1.status); // Available
book1.checkout(); // "JavaScript Mastery" checked out successfully.
book1.checkout(); // "JavaScript Mastery" is already checked out.
console.log(book1.status); // Checked Out
book1.returnBook(); // "JavaScript Mastery" returned. Thank you!
console.log(book1.status); // AvailableKey Points to Remember
- A class is a blueprint for creating objects with shared properties and methods
- The
constructor()runs automatically when a new instance is created withnew thisrefers to the current instance inside a class- Use
extendsfor inheritance andsuper()to call the parent constructor - Static methods belong to the class, not to instances — called directly on the class name
- Getters and setters provide controlled access to properties
- Private fields (prefixed with
#) are accessible only within the class - Method overriding allows child classes to redefine parent methods
- Use
instanceofto check if an object is an instance of a class
