Mastering Classes and Object-Oriented Programming in JavaScript

In a world where code is king, mastering classes and object-oriented programming (OOP) in JavaScript can set you apart. If you've ever wondered how experienced developers create clean, reusable code, the answer lies in OOP principles and using JavaScript classes effectively.

Let’s dive into how JavaScript classes work, understand OOP concepts, and explore practical examples to elevate your coding skills.

What is Object-Oriented Programming in JavaScript?

Object-Oriented Programming (OOP) is a paradigm where the code is organized around objects, rather than functions and logic alone. It helps developers create modular code that’s easy to read, manage, and extend. In JavaScript, OOP is implemented using classes, prototypes, and a set of principles like encapsulation, inheritance, and polymorphism.

Core Principles of OOP:

  1. Encapsulation: Group related variables and functions in a single unit, an object, or class.

  2. Inheritance: Allow new classes to extend existing ones, reusing code effectively.

  3. Polymorphism: Give a single interface multiple implementations.

  4. Abstraction: Expose only essential features and hide unnecessary details.

JavaScript Classes: The Building Blocks of OOP

JavaScript classes, introduced in ES6, provide a clean, syntactic sugar to define objects and enable OOP practices. While JavaScript remains a prototype-based language under the hood, classes provide a clearer structure.

Defining a Class in JavaScript

Let’s create a simple Car class as an example.

class Car {
  constructor(brand, model) {
    this.brand = brand;
    this.model = model;
  }

  start() {
    console.log(`${this.brand} ${this.model} is starting...`);
  }

  drive() {
    console.log(`${this.brand} ${this.model} is on the move!`);
  }
}

const myCar = new Car('Toyota', 'Camry');
myCar.start();  // Output: "Toyota Camry is starting..."
myCar.drive();  // Output: "Toyota Camry is on the move!"

The Car class has a constructor method that initializes its properties (brand and model). The start and drive methods add functionality to instances of the Car class.

Key Concepts in JavaScript OOP

1. Constructor Functions

The constructor function is a special method in a class that runs when an object is created. It’s commonly used to set initial properties.

constructor(brand, model) {
  this.brand = brand;
  this.model = model;
}

Here, constructor sets brand and model properties when a new Car instance is created.

2. Encapsulation in JavaScript

Encapsulation lets us bundle data and methods into a single unit. In JavaScript, we can use classes and closures to achieve encapsulation, helping us protect data from unintended modification.

class Car {
  constructor(brand, model) {
    this._brand = brand;
    this._model = model;
  }

  getDetails() {
    return `${this._brand} ${this._model}`;
  }
}

The underscore (_) prefix conventionally marks properties as private (even though JavaScript doesn’t have true private properties outside of recent # syntax).

3. Inheritance in JavaScript

Inheritance allows us to create new classes based on existing ones. Let’s create an ElectricCar class that extends Car:

class ElectricCar extends Car {
  constructor(brand, model, batteryLife) {
    super(brand, model);  // Call the parent constructor
    this.batteryLife = batteryLife;
  }

  chargeBattery() {
    console.log(`Charging the battery of ${this.brand} ${this.model}.`);
  }
}

const myElectricCar = new ElectricCar('Tesla', 'Model S', '100 kWh');
myElectricCar.start();         // Inherited method
myElectricCar.chargeBattery();  // New method specific to ElectricCar

Using extends and super(), ElectricCar inherits methods from Car, allowing us to reuse code.

4. Polymorphism in JavaScript

Polymorphism lets us define multiple behaviors for the same function, depending on the object’s context. For example:

class Animal {
  speak() {
    console.log("The animal makes a sound.");
  }
}

class Dog extends Animal {
  speak() {
    console.log("The dog barks.");
  }
}

const myDog = new Dog();
myDog.speak();  // Output: "The dog barks."

The speak method behaves differently depending on the class (Animal or Dog), demonstrating polymorphism.

Best Practices for OOP in JavaScript

  • Use encapsulation to protect object properties.

  • Keep classes focused on a single responsibility.

  • Use inheritance thoughtfully to avoid over-complexity.

  • Write modular, reusable code that can be extended.

Advantages of Using OOP in JavaScript

  1. Code Reusability: Inheritance allows you to reuse existing code across classes.

  2. Code Maintenance: Modular classes make the code easier to read and maintain.

  3. Debugging: Grouping code into classes simplifies the debugging process.

  4. Scalability: OOP helps build scalable, large applications by promoting organized code structure.

Real-World Example: Shopping Cart System

Let’s create a simple shopping cart system to see OOP in action.

class Product {
  constructor(name, price) {
    this.name = name;
    this.price = price;
  }
}

class Cart {
  constructor() {
    this.items = [];
  }

  addItem(product) {
    this.items.push(product);
  }

  calculateTotal() {
    return this.items.reduce((total, product) => total + product.price, 0);
  }
}

const apple = new Product('Apple', 0.5);
const bread = new Product('Bread', 2);
const cart = new Cart();

cart.addItem(apple);
cart.addItem(bread);
console.log(`Total: $${cart.calculateTotal()}`);  // Output: "Total: $2.5"

In this example:

  • Product is a simple class representing an item with a name and price.

  • Cart is another class that adds products and calculates the total.

JavaScript OOP: Classes vs Functions

Classes in JavaScript offer a more structured approach to creating objects compared to functions alone. While functions can also create objects, classes provide a cleaner syntax and built-in methods, making the code easier to understand and maintain.

// Function-based constructor
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person1 = new Person('Alice');
person1.greet();

While this approach works, ES6 classes bring more readability and consistency.

Wrapping Up

JavaScript classes and OOP principles like encapsulation, inheritance, and polymorphism can transform your code into an organized, reusable structure that’s easier to maintain and scale.

Whether you’re building complex applications or simpler features, understanding OOP will make you a more effective JavaScript developer.

0
Subscribe to my newsletter

Read articles from Stanley Owarieta directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Stanley Owarieta
Stanley Owarieta

𝗔𝘀𝗽𝗶𝗿𝗶𝗻𝗴 𝗙𝗿𝗼𝗻𝘁𝗲𝗻𝗱 𝗗𝗲𝘃𝗲𝗹𝗼𝗽𝗲𝗿 passionate about 𝙅𝙖𝙫𝙖𝙎𝙘𝙧𝙞𝙥𝙩, 𝙘𝙤𝙙𝙞𝙣𝙜, 𝙖𝙣𝙙 𝙗𝙪𝙞𝙡𝙙𝙞𝙣𝙜 𝙢𝙮 𝙛𝙪𝙩𝙪𝙧𝙚 𝙞𝙣 𝙩𝙚𝙘𝙝. Along with my 𝙡𝙤𝙫𝙚 for 𝙛𝙖𝙨𝙝𝙞𝙤𝙣, 𝙜𝙖𝙢𝙞𝙣𝙜, 𝙖𝙣𝙙 𝙡𝙪𝙭𝙪𝙧𝙮 𝙡𝙞𝙫𝙞𝙣𝙜, I have big dreams like 𝙤𝙬𝙣𝙞𝙣𝙜 𝙖 𝙥𝙧𝙞𝙫𝙖𝙩𝙚 𝙟𝙚𝙩 and 𝙡𝙞𝙫𝙞𝙣𝙜 𝙞𝙣 𝙖 𝙡𝙪𝙭𝙪𝙧𝙮 𝙝𝙤𝙢𝙚 𝙤𝙣𝙚 𝙙𝙖𝙮. Since 2021, I’ve invested in 𝗔𝗽𝗽𝗹𝗲, 𝗔𝗺𝗮𝘇𝗼𝗻, 𝗦𝗵𝗼𝗽𝗶𝗳𝘆, 𝗮𝗻𝗱 𝗚𝗼𝗼𝗴𝗹𝗲—working toward financial independence. I also look forward to being a 𝗹𝗼𝘃𝗶𝗻𝗴 𝗳𝗮𝘁𝗵𝗲𝗿 𝗮𝗻𝗱 𝗮 𝗱𝗲𝘃𝗼𝘁𝗲𝗱 𝗽𝗮𝗿𝘁𝗻𝗲𝗿, growing a 𝗺𝗶𝗹𝗹𝗶𝗼𝗻-𝗱𝗼𝗹𝗹𝗮𝗿 𝗯𝗿𝗮𝗻𝗱 together with my 𝗳𝘂𝘁𝘂𝗿𝗲 𝘄𝗶𝗳𝗲. Let’s connect and inspire each other on this journey!