All You Need to Know About JavaScript Object-Oriented Programming (OOP)

·

9 min read

All You Need to Know About JavaScript Object-Oriented Programming (OOP)

In JavaScript, Object-Oriented Programming (OOP) is a fundamental concept that is used to organize your code into reusable and structured components. By breaking down your code into structured components, you can enhance its readability and maintainability. In this blog post, we'll cover the concepts of Object-Oriented Programming (OOP).

Let's start!

What is Object-Oriented Programming (OOP)?

Object-Oriented Programming is a programming paradigm (a way of writing code) that centres on the idea of "objects". These objects can be thought of as building blocks to create things.

In OOP, you create these objects based on a blueprint known as a "class". It's like making many cars using the same car blueprint. Each car shares the same design principles, structure, and features defined in the blueprint, but they can still have their own unique characteristics, such as colour or accessories.

OOP helps you keep your code organized and makes it easier to understand how different parts of your program interact with each other.

Classes and Constructors

A class is a blueprint for creating objects with similar properties and methods. Constructors are functions used to create and initialize objects based on that class's blueprint.

For example:

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

In the above example, Car is our blueprint and the constructor(company, model) is like a set of instructions we follow to create a new car with the given "company" and "model."

In other words, a class is like a plan for creating objects, and the constructor is the set of instructions that every new object follows to get its initial details.

Creating Objects

Once we have a class, we can create objects(instances) using the new keyword.

const carObject = new Car('Ford', 'Mustang');

Prototype

The prototype is a property that allows objects to take properties and methods from other objects.

Every object in JavaScript has a prototype property. When we try to access a property or method on an object, JavaScript first checks if that property or method exists on the object itself. If it doesn't, JavaScript looks up the prototype object. If the prototype doesn't have it, JavaScript keeps looking at "parent" prototypes until it finds the property or method.

To put it simply, think of it as borrowing things from a friend. If you don't have something, you ask your friend. If your friend doesn't have it, they might ask their friend, and this can continue until someone has what you're looking for.

For example:

//class and constructor
class Car {
  constructor(company, model) {
    this.company = company;
    this.model = model;
  }
}

//Adding a method to the prototype of Car
Car.prototype.hello = function() {
    console.log(`Hello, I'm ${this.model} model of ${this.company} company!`);
};

// Creating objects using the Car constructor
const carObject1 = new Car('Ford', 'Mustang');
const carObject2 = new Car('Toyota', 'Fortuner');

carObject1.hello(); // Output: Hello, I'm Mustang model of Ford company!
carObject2.hello(); // Output: Hello, I'm Fortuner model of Toyota company!

In the above example, the hello method is defined in the Car.prototype. When we create objects using new Car(), they automatically inherit the hello method from the prototype.

In other words, when carObject1.hello() is called, JavaScript first checks if hello exists on the carObject1, and if it doesn't, it looks in the Car.prototype.

You can also add methods inside the class. For example:

//class and constructor
class Car {
  constructor(company, model) {
    this.company = company;
    this.model = model;
  }
  hello() { //Adding a method to the prototype of Car
    console.log(`Hello, I'm ${this.model} model of ${this.company} company!`);
  }
}

// Creating objects using the Car constructor
const carObject1 = new Car('Ford', 'Mustang');
const carObject2 = new Car('Toyota', 'Fortuner');

carObject1.hello(); // Output: Hello, I'm Mustang model of Ford company!
carObject2.hello(); // Output: Hello, I'm Fortuner model of Toyota company!

this keyword

The this keyword refers to the current object or instance that a method is being called on.

It represents the object that a function or method belongs to and helps to access the object's properties and methods from within its functions.

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

  hello() {
    console.log(`Hello, I'm ${this.name}!`);
  }
}

const person1 = new Person('John');
const person2 = new Person('Mark');

person1.hello(); // Output: Hello, I'm John!
person2.hello(); // Output: Hello, I'm Mark!

Class Inheritance

Class inheritance is a method of one class to inherit properties and methods from another class. This can be done using the extends keyword.

For example, we want to add a year property to our Car blueprint.

//parent class
class Car {
  constructor(company, model) {
    this.company = company;
    this.model = model;
  }
}
//child class
class carYear extends Car{
  constructor(company, model, year) {
    super(company, model); // Call the constructor of the parent class
    this.year = year;
  }
}
// Creating object using the carYear constructor
const carObject = new carYear('Ford', 'Mustang', 1969);

console.log(carObject.company + " " + carObject.model + " " + carObject.year); 
//Output: Ford Mustang 1969

Calling the constructor of the parent class into the child class using the super keyword is known as constructor overriding.

super keyword

The super keyword is used to call and access methods or properties from a parent class within a child class.

Method Overriding

Method overriding allows you to change or replace a method's behavior in a child class while keeping the same method name as the parent class.

For example:

//parent class
class Car {
  constructor(company, model) {
    this.company = company;
    this.model = model;
  }
}
//Adding a method to the prototype of Car
Car.prototype.hello = function() {
    console.log(`Hello, I'm ${this.model} model of ${this.company} company!`);
};

//child class
class carYear extends Car{
  constructor(company, model, year) {
    super(company, model); // Call the constructor of the parent class
    this.year = year;
  }
}
//Adding a method to the prototype of carYear
carYear.prototype.hello = function() {
    console.log(`Hello, I'm ${this.year} ${this.model} model of ${this.company} company!`);
};

// Creating object using the Car constructor
const carObject = new Car('Ford', 'Mustang');

// Creating object using the carYear constructor
const carYearObject = new carYear('Ford', 'Mustang', 1969);

carObject.hello(); //Hello, I'm Mustang model of Ford company!
carYearObject.hello(); //Hello, I'm 1969 Mustang model of Ford company!

In the above example, we have a Car class with a method hello()and a carYear class that extends Car. In the carYear class, we override the hello() method. When we create an object of the carYear class and call the hello() method, it uses the overridden method from the carYear class, not the one from the Car class. This is method overriding.

Static Methods

Static methods are methods that are associated with a class rather than with objects of the class. They are called on the class itself, not on objects of the class. Static methods are defined using the static keyword within a class declaration.

class Car {
  constructor(company, model) {
    this.company = company;
    this.model = model;
  }
  start() { 
  console.log(`${this.model} of ${this.company}  is starting...`);
  }
  static info() {
  console.log("This is a Car class.");
 }
}

// Creating object of the Car class
const carObject = new Car('Ford', 'Mustang');

// Calling object methods 
carObject.start(); // Mustang of Ford  is starting...

// Calling static method
Car.info(); // This is a Car class.

Getters and Setters

Getters and setters are special methods that allow us to define how properties of an object are accessed (getter) and modified (setter).

For example:

class Car {
  constructor(company, model) {
    this._company = company;
    this._model = model;
  }

  // Getter for the company property
  get company() {
    return this._company;
  }

  // Setter for the company property
  set company(newCompany) {
    if (typeof newCompany === 'string') {
      this._company = newCompany;
    } else {
      console.log("company must be a string");
    }
  }

  // Getter for the model property
  get model() {
    return this._model;
  }

  // Setter for the model property
  set model(newModel) {
    if (typeof newModel === 'string') {
      this._model = newModel;
    } else {
      console.log("model must be a string");
    }
  }
};

// Creating an object of the Car class
const carObject = new Car('Ford', 'Mustang');

// Using getter for company
console.log(`Company: ${carObject.company}`); //Output- Company: Ford

// Using setter for company
carObject.company = 'Toyota'; 
console.log(`Company: ${carObject.company}`); //Output- Company: Toyota

// Using getter for model
console.log(`Model: ${carObject.model}`); //Output- Model: Mustang

// Using setter for model
carObject.model = 'Fortuner'; 
console.log(`Model: ${carObject.model}`); //Output- Model: Fortuner

//Try to set invalid value
carObject.model = 3; //Output- model must be a string

In the above example, the Car class has getter and setter methods for the company and model properties. The getters allow you to retrieve the values of these properties, while the setters provide a way to validate and set new values for the properties.

Here, the underscores _company and _model are used to indicate that these properties are meant to be private to the Car class and should not be accessed or modified directly from outside the class.

instanceof Operator

The instanceof operator is used to check whether an object is an instance of a particular class or constructor function.

For example:

//parent class
class Car {
  constructor(company, model) {
    this.company = company;
    this.model = model;
  }
}

//child class
class carYear extends Car{
  constructor(company, model, year) {
    super(company, model); 
    this.year = year;
  }
}

// Creating object using the Car constructor
const carObject = new Car('Ford', 'Mustang');

// Creating object using the carYear constructor
const carYearObject = new carYear('Ford', 'Mustang', 1969);

//Using instanceof operator

console.log(carObject instanceof Car); // true
console.log(carObject instanceof carYear); // false

console.log(carYearObject instanceof Car); // true
console.log(carYearObject instanceof carYear); // true

In the above example, we have a Car class and a carYear class that inherits from Car. We create instances(objects) of both classes and then use the instanceof operator.

carObject is an instance of Car, but it's not an instance of carYearObject. carYearObject is an instance of both Car and carYear.

Conclusion

In JavaScript, Object-Oriented Programming (OOP) is a paradigm that revolves around the concept of objects, which are created based on class blueprints.

Key concepts covered in this blog post include:

  1. Classes and Constructors: A class is a blueprint for creating objects with similar properties and methods. Constructors are functions used to create and initialize objects based on that class's blueprint.

  2. Prototype: The prototype is a property that allows objects to take properties and methods from other objects.

  3. The 'this' Keyword: 'this' refers to the current object or instance and is used to access its properties and methods within functions or methods.

  4. Class Inheritance: The 'extends' keyword enables one class to inherit properties and methods from another class.

  5. Super Keyword: 'super' is used to call and access methods or properties from a parent class within a child class.

  6. Method Overriding: Child classes can override parent class methods to modify behavior while keeping the same method name.

  7. Static Methods: Static methods belong to the class itself and are called on the class, not on object instances.

  8. Getters and Setters: Getters retrieve property values, and setters validate and set new property values, allowing controlled access to object properties.

  9. instanceof Operator: The instanceof operator is used to determine if an object is an instance of a particular class or constructor function.

By mastering these OOP concepts, JavaScript developers can create well-structured, modular, and maintainable code that efficiently models real-world entities and interactions.

Thanks for reading!

Keep Coding!

For more content click here!