Learn Object Oriented Programming Javascript In 2024

Telegram Group Join Now
WhatsApp Group Join Now

One of the most widely used programming languages worldwide is JavaScript. For this, a lot of JavaScript developers begin by studying the fundamentals of the language, including variables, functions, loops, etc. In the future, you should pick up advanced skills like object-oriented programming (OOP). More reusable and maintainable code can be written with JavaScript’s object-oriented features.

We’ll break down the main concepts of object-oriented programming (OOP) in JavaScript in this blog so you can write object-oriented programmes with confidence.

What is Object Oriented Programming?

OOP is a programming paradigm centered around the concept of objects. Objects allow us to model real world things and encapsulate their properties and behaviors into reusable chunks of code.

For example, we can use a Car object with properties like make, model, and colour to represent a car. Further, the car may have features like drive, brake, park, and so forth. To keep our code organised, we bundle together properties and behaviours that are connected into objects.

The main pillars of OOP are:

  • Encapsulation – Grouping related properties and methods into objects
  • Abstraction – Reducing complexity by hiding unnecessary details from other objects
  • Inheritance – Objects can inherit commonly used properties and methods from other objects
  • Polymorphism – Objects can share the same interface (method names) but have different implementations

This allows us to write more modular, reusable code. Instead of having fragmented, disorganized procedures, OOP allows us to think in terms of self-contained objects.

Why Use OOP in JavaScript?

You may be wondering, if I can write JavaScript code without worrying about objects, why bother learning OOP? There are a few key reasons:

learn object oriented programming javascript
  • Organization – OOP forces you to think about how to logically structure your code into reusable pieces. This leads to code that is better organized.
  • Reusability – Once you create a class, you can instantiate new objects from it over and over again. This saves you from rewriting code.
  • Collaboration – Objects can interact with one another through clearly defined interfaces. This helps facilitate collaboration in large codebases with many developers.
  • Maintenance – Code structured in objects is modular and encapsulated, making it easier to maintain over time as requirements change.

The benefits become even more apparent as an application grows in size and complexity. While OOP has a steeper initial learning curve, it pays off in the long run with code that is easier to read, reuse, maintain, and build upon. That’s why most large applications are written using object oriented principles.

Object Oriented JavaScript Basics

JavaScript is a multi-paradigm language. Unlike class-based languages like Java or C++, JavaScript didn’t originally have built-in features for defining classes or class inheritance. However, over the years JavaScript has gradually added more OOP capabilities.

Today, while JavaScript remains a prototype-based language, we can effectively use OOP in JavaScript thanks to newer features like classes and class inheritance. Let’s break down the key concepts.

Objects

In JavaScript, nearly everything is an object. Objects are collections of name-value pairs. We define keys and values separated by colons:

const person = {
  name: 'Rupnath',
  age: 30
}

We can access properties using dot notation or square brackets:

person.name // 'Rupnath' 
person['age'] // 30

Objects in JavaScript are dynamic – we can freely add, remove, or modify properties at any time:

person.job = 'Web Developer'

delete person.age

This flexibility makes objects in JavaScript extremely powerful.

Methods

Methods are functions defined as object properties:

const person = {
  name: 'Rupnath',
  greet() {
    console.log(`Hello, my name is ${this.name}!`)
  }
}

person.greet() // Logs "Hello, my name is Rupnath!"

Methods allow objects to “act” – they define object behavior.

Classes

The class syntax was introduced to JavaScript in ES6. It provides a cleaner way to create objects and implement shared functionality.

Classes are like object templates. They define properties and methods that will be present in all objects instantiated from that class:

class Person {
  constructor(name) {
    this.name = name
  }
  
  greet() {
    console.log(`Hello, my name is ${this.name}!`)
  }
}

const john = new Person('Rupnath')
john.greet() // "Hello, my name is John!"
  • constructor() runs when a new class instance is created
  • The this keyword refers to the current class instance
  • new creates a new object instance from the class

Classes allow us to reuse code by instantiating multiple objects with the same structure/behavior.

Inheritance

Classes can inherit properties and methods from other classes using the extends keyword:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}!`);
  }
}

class Employee extends Person {
  constructor(name, title) {
    super(name);  // Call the parent class constructor
    this.title = title;
  }

  greet() {
    super.greet(); // Call the parent class greet method
    console.log(`I am a ${this.title}`);
  }
}

const employee = new Employee('Rupnath', 'Web Developer');
employee.greet();  // Call greet after creating the employee object

// Hello, my name is Rupnath!
// I am a Web Developer
  • The subclass inherits properties/methods from the parent class
  • super() calls the parent constructor
  • Child classes can override parent methods

This allows us to reuse parent class logic while specializing in child class behavior.

Key Principles of OOP in JavaScript

Now that we’ve covered some syntax basics, let’s go over key object oriented principles and how they are applied in JavaScript:

Encapsulation

Encapsulation means grouping related properties and methods together into an object. This keeps data and behavior in one place and hides internal implementation details from other objects.

For example, we can encapsulate person data:

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

const person1 = new Person('John', 30)

And hide internal implementation details:

class Person {

  constructor(name, age) {
    this.name = name
    this.privateAge = age
  }

  getAge() {
    return this.privateAge 
  }

  incrementAge() {
    this.privateAge++
  }

}

const person1 = new Person('John', 30)
person1.getAge() // 30

person1.incrementAge()

person1.getAge() // 31

By using closures and private properties only exposed through public methods, we can control access to the internal state from outside the Person object.

Abstraction

Abstraction means hiding complexity by exposing only essential features of an object or system. We can create abstract classes that provide skeleton methods without implementation details:

class Animal {
  constructor(name) {
    this.name = name
  }

  eat() {
    throw new Error('Animal subclass must implement eat method')
  }

}

class Dog extends Animal {

  constructor(name) {
    super(name)
  }
  
  eat() {
    console.log(`${this.name} is eating dog food`)
  }

}

const rover = new Dog('Rover')

rover.eat() // Rover is eating dog food

This abstracts away the implementation details to the subclasses.

Inheritance

Inheritance allows a child class to inherit properties and methods from a parent class:

class Employee extends Person {
  constructor(name, title) {
    super(name)
    this.title = title
  }
}

const employee = new Employee('Rupnath', 'Web Developer')

The Employee class inherits the name property from Person so we don’t have to redefine it.

Inheritance promotes code reuse in a hierarchical taxonomy of classes.

Polymorphism

Polymorphism allows objects to share interfaces while maintaining unique implementations. For example:

class Animal {

  constructor(name) {
    this.name = name
  }

  makeSound() {
    throw new Error('Abstract method - must be implemented by subclass') 
  }

}

class Dog extends Animal {

  constructor(name) {
    super(name)
  }

  makeSound() {
    console.log('Bark!')
  }

}

class Cat extends Animal {

  constructor(name) {
    super(name)
  }

  makeSound() {
    console.log('Meow!')
  }

}

const dog = new Dog('Rover')
dog.makeSound() // Bark!

const cat = new Cat('Fluffy')
cat.makeSound() // Meow!

Even though Dog and Cat have different implementations, we can call makeSound() on any Animal. This makes our code more flexible and reusable.

Putting it All Together: A Case Study

Let’s see how we can utilize these object oriented principles to build out an application feature.

Imagine we are building the Person management system for a company HR application. Employees in the system should have properties like name, email, jobTitle, etc. as well as methods to getBonus() and applyRaise().

There are also different employee types like engineers, designers, managers, etc. Each employee type needs specialized methods – for example an Engineer can writeCode() while a Manager can generateReport().

Let’s model some of this using OOP techniques:

// Base Person class

class Person {

  constructor(name, email) {
    this.name = name
    this.email = email
  }

  notify(message) {
    console.log(`Email sent to ${this.email}: ${message}`) 
  }

}

// Employee subclass
class Employee extends Person {

  constructor(name, email, jobTitle) {
    super(name, email)
    this.jobTitle = jobTitle
  }

  getBonus() {
    return this.jobTitle === 'Manager' ? 1000 : 500
  }

  applyRaise() {
    // Apply raise logic...
  }

}

// Engineer subclass 
class Engineer extends Employee {

  constructor(name, email) {
    super(name, email, 'Engineer')
  }

  writeCode() {
    console.log(`${this.name} is writing code...`)
  }

}

// Instantiate objects
const thomas = new Engineer('Thomas', 'thomas@company.com')

thomas.writeCode() // Thomas is writing code...

thomas.getBonus() // 500

thomas.notify('Here is your bonus amount') 

// Email sent to thomas@company.com: Here is your bonus amount

This allows us to:

  • Encapsulate the Person and Employee data and behaviors
  • Abstract away implementation details in parent classes
  • Inherit shared properties and methods like name and getBonus()
  • Polymorph the notify() method to work for any Person or Employee

The result is clean, organized, reusable code! We can easily add new employee types and build on this object hierarchy.

Key Takeaways

Here are some key takeaways:

  • Object oriented programming centers around encapsulating state and behavior into objects
  • OOP provides organization, reusability and collaboration benefits
  • JavaScript is well-suited for OOP, with object literals, classes and inheritance
  • Encapsulation, abstraction, inheritance and polymorphism are core OOP principles
  • We can build object hierarchies to efficiently model complex systems

While OOP has a steeper learning curve, it enables you to write more modular, scalable JavaScript codebases as your applications grow.

I hope this article has demystified some object oriented JavaScript concepts and given you a solid foundation to start applying OOP techniques in your code.

Leave a comment