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 behaviour 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:
- 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.
- Prototype: The prototype is a property that allows objects to take properties and methods from other objects.
- The ‘this’ Keyword: ‘this’ refers to the current object or instance and is used to access its properties and methods within functions or methods.
- Class Inheritance: The ‘extends’ keyword enables one class to inherit properties and methods from another class.
- Super Keyword: ‘super’ is used to call and access methods or properties from a parent class within a child class.
- Method Overriding: Child classes can override parent class methods to modify behaviour while keeping the same method name.
- Static Methods: Static methods belong to the class itself and are called on the class, not on object instances.
- Getters and Setters: Getters retrieve property values, and setters validate and set new property values, allowing controlled access to object properties.
instanceof
Operator: Theinstanceof
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!
Check out toast.log, a browser extension that lets you see errors, warnings, and logs as they happen on your site — without having to open the browser’s console. Click here to get a 25% discount on toast.log.