Object Oriented Programming (OOP): A general overview
Object oriented programming is a type of programming style which revolves around the concepts of objects (literally real-life objects e.g., a house that can have different properties). Your code is structured and designed based on objects. Each object combines properties and methods that can be performed on that data into a single unit.
In JavaScript an object is a collection of key-value pairs (keys are the properties and values are the different data types or functions). Objects can be created in several ways, object literals, constructor functions and classes (ES6). The best way to define an object in JS depends on the specific context and your programming goals. Each method has its own advantages and disadvantages.
Object Literals: Object literals can be used when you need a simple object with few properties and methods, great for a quick and straight forward object creation.
const School = {
name: "Obafemi Awolowo University",
country: "Nigeria",
state: "Osun state",
welcome: () => {
console.log("Welcome to Great Ife!!");
}
}
// console.log(School);
// console.log(School.name) <= Calling the object using dot notation.
Constructor functions: The constructor function is used when you plan to create multiple instances of similar objects, with the same properties and methods they are used for creating objects blueprints.
The this keyword refers to the correct object in JavaScript is a way to access and manipulate the properties and methods of the objects within which it is used. The behavior of this depends on the context in which it is used, its value is dynamically determined on runtime based on how a function is invoked. As it is used in a constructor function it refers to the object being created (i.e., instance of a class). It allows you to set the properties of that instance.
function School (name, country, state) => {
this.name = name;
this.country = country;
this.state = state;
this.welcome = function () {
console.log("Welcome to Great Ife");}
}
ES6 class: The ES6 class is a similar version of the constructor function but it takes advantage of a more modern class syntax, it is more organized, and it is used for much larger and complex projects.
class School {
constructor (name, country, state)
this.name = name,
this.country = country,
this.state = state
}
Principles of Object-Oriented Programming
Encapsulation: This one of the fundamental principles of OOP in which data or properties are bonded together into a single unit known as a class. Imagine you have a bottle of water, the water in the bottle is like your data (something you want safe), the cover of the bottle is like the method that allows you access the function. The bottle itself is like a protective layer for preventing the water from spilling until you open it when you need it. In this case encapsulation is like this, data is kept in like a method or a function with a cover that controls how you access the data.
class Person {
constructor(name, age) {
// Private properties (prefixing with an underscore convention) the water in this case
this._name = name;
this._age = age;
}
// The below is the method in which they can be accessed like the cover of the bottle
getName() {
return this._name;
}
getAge() {
return this._age;
}
celebrateBirthday() {
this._age++;
}
}
const person1 = new Person("Alice", 25);
const person2 = new Person("Bob", 30);
console.log(person1.getName()); // Outputs: Alice
console.log(person1.getAge()); // Outputs: 25
console.log(person2.getName()); // Outputs: Bob
console.log(person2.getAge()); // Outputs: 30
person1.celebrateBirthday();
console.log(person1.getAge()); // Outputs: 26
Polymorphism: This also another vital principle of OOP that allows objects of different classes to be treated as if they are objects of a common superclass. This is like having a universal remote that works with different brands of TVs irrespective of its model, the remote performs actions like increasing or decreasing the volume of the TV, switching on or turning off the TV. In the programming world you can have different types of objects (TV) that are responding to the same function (remote). Polymorphism provides flexibility and extensibility in code, making it easier to work with diverse objects in a uniform manner.
class Vehicle {
drive () => {
console.log("This vehicle is generic")
}
};
class Car extends Vehicle {
drive() => {
console.log("I am actually driving a car!!")
};
};
class Bicycle extends Vehicle {
drive () => {
console.log("I am riding a bicycle");
}
};
class Boat extends Vehicle {
drive () => {
console.log("I am sailing a boat")
}
}
const myCar = new Car();
const myBicycle = new Bicycle();
const myBoat = new Boat();
const vehicles = [myCar, myBicycle, myBoat];
vehicles.forEach(vehicle => {
vehicle.drive();
});
Inheritance: It is a principle in OOP that allows a new class to inherit properties and methods from an existing class. This promotes the reuse and the creation of hierarchies. Think of a family, the grandparents, parents and the children, the grandparents pass on some characteristics e.g., hair color or eye color to the parent and the parents pass on other characteristics like height or intelligence to the child. Inheritance in programming is similar, you can create new classes (child classes) that inherit attributes and methods from existing classes (parent classes).
// Parent class
function Animal(name) {
this.name = name;
}
// Method shared by all animals
Animal.prototype.sayHello = function () {
console.log(`Hello, I am ${this.name}.`);
}
// Child class that inherits from Animal
function Dog(name, breed) {
Animal.call(this, name); // Call the parent constructor
this.breed = breed;
}
// Set up the prototype chain for inheritance
Dog.prototype = Object.create(Animal.prototype);
// Method specific to Dog
Dog.prototype.bark = function () {
console.log('Woof! Woof!');
}
// Create instances
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.sayHello(); // Outputs: Hello, I am Buddy.
myDog.bark(); // Outputs: Woof! Woof.
Abstraction: This is a concept in OOP that allows us to hide the unnecessary details of an object from a user. Abstraction helps us reduce complexity and improve the readability in code. Imagine you have a remote that controls the TV, you don’t need to know how the TV works or the science behind it, also imagine a car, you don’t really need to know how the brakes or the engine works, you are just concerned with higher functions like the steering wheel, this is exactly how abstraction in OOP works, it masks out the hidden details so that the higher details can be utilized.
class BankAccount {
constructor(accountNumber, accountHolder) {
this.accountNumber = accountNumber;
this.accountHolder = accountHolder;
this.balance = 0; // Abstraction: We don't need to know the details of the balance calculations.
}
// Public methods for interacting with the account
deposit(amount) {
this.balance += amount;
console.log(`Deposited $${amount}. New balance: $${this.balance}`);
}
withdraw(amount) {
if (amount <= this.balance) {
this.balance -= amount;
console.log(`Withdrawn $${amount}. New balance: $${this.balance}`);
} else {
console.log("Insufficient funds.");
}
}
getBalance() {
console.log(`Account balance: $${this.balance}`);
}
}
// Using the BankAccount class
const myAccount = new BankAccount("12345", "John Doe");
myAccount.deposit(1000); // Outputs: Deposited $1000. New balance: $1000
myAccount.withdraw(500); // Outputs: Withdrawn $500. New balance: $500
myAccount.getBalance(); // Outputs: Account balance: $500
Benefits of OOP
- It promotes modularity by organizing code into objects and classes.
- It has improved the reusability of code through polymorphism and inheritance.
- It makes code easier to maintain and easy to understand.
- It supports scalability of software development.
- It improves the organization of code making it clear and easier to navigate.
- It promotes collaboration and simplifies complex systems by breaking them into smaller objects.
- In OOP it is easier to translate real world problems into software solutions.
Limitations of OOP
- It has a steep learning curve most especially for beginners.
- It can be inefficient for some tasks especially tasks that are not naturally object oriented.
- OOP can be very rigid one slight change can affect the whole codebase.
- Overusing of one of the principles of OOP inheritance can lead to the “diamond problem” (ambiguity in multiple inheritance).
Object-Oriented programming or Functional programming?
The choice between OOP and FP depends on your project requirements, each programming paradigm has its pros and cons. OOP is a good fit for modeling complex systems where you can represent the problem domain as objects while FP is a good choice for data transformation, data processing, and parallel computing. A combination of OOP and FP provides a more balanced and pragmatic approach for solving complex problems.
Overall, OOP is a good paradigm to learn and understand, that provides a structured and organized way to design and develop software systems. Here are some links that will enable you gain more insight of OOP; Udacity, geeksforgeeks , W3Schools, MDNdocs. Have a wonderful learning process 😊.