This article will provide an overview of the four pillars of object oriented programming (OOP), including a look at a few concepts related to OOP and steps for implementing OOP concepts in JavaScript.
Why Use Object-Oriented Programming?
Writing highly readable code is crucial in programming because it promotes code reusability and scalability; OOP helps us achieve this.
We have shared that the top 3 object-oriented programming languages are Java, Python and C++, though some great alternatives include JavaScript and C#. OOP focuses on organizing software around specific data or objects rather than around the logic required to manage them. In essence, OOP models a system as a collection of data called objects, and each object represents a part of the system.
Certain features make up the foundation for a language to be considered object-oriented:
Classes
These are user-defined data types that are grouped together. They share similar attributes and serve as a template for creating objects.
Methods
Methods are functions defined inside a class. They dictate how an object will behave. They are used to keep functionality encased in an object.
Objects
These unique entities contain methods and properties. They are instances of a class created with specifically defined data.
Attributes
This is a characteristic that defines the state of an object. It is used to manipulate or reference a class’s property.
Why is OOP Important?
There are several benefits of object-oriented programming:
- Code re-usability as a result of inheritance allows the use of properties from the main class in a new subclass.
- It also improves general productivity by allowing developers to create programs more quickly.
- It makes collaborative development and troubleshooting much more straightforward.
- It improves code scalability significantly.
- It makes software maintenance much more accessible by hiding complex code and protecting parts of the code.
- It allows more flexibility through polymorphism; since a single function can be modified to adapt to the class that it's placed in.
What are the Four Pillars of Object Oriented Programming?
There are four pillars of object oriented programming that apply to supported languages:
Abstraction
This is the process of refactoring complex code, making objects reveal only internal mechanisms that other objects require. This OOP concept allows developers to quickly make changes or additions to the code over time.
Encapsulation
The principle of encapsulation ensures that code is only used as intended by securing important information inside an object and allowing only a selection of information to be exposed. The values and data cannot be manipulated because they are held privately inside a defined class. Other objects do not have the authority to make changes; they can only call public functions in the class. This pillar of OOP provides a greater level of program security and avoids unintentional tampering.
Inheritance
Inheritance allows classes to reuse code from other classes. For example, there is one class called the main class with all the primary features, and then another called the sub-class, which inherits all the functionality from the main class. This allows developers to reuse common logic while maintaining a unique hierarchy. This practice ensures a higher level of accuracy and reduced development time.
Polymorphism
When an object shares traits with a class, there are certain times when changes need to be made to the behaviors inherited from the main class. Polymorphism helps by allowing us to override functions inherited from the main class in a sub-class. This OOP pillar helps reduce the amount of duplicated code.
Implementing Principals of Object Oriented Programming in JavaScript
Object Literals for Abstraction
An object in JavaScript is a collection of data and similar functionality. It mostly consists of variables and functions (known as properties and methods) separated by commas. Objects can also contain other objects within them.
Abstraction requires that we package code into more uncomplicated form factors, and objects are a perfect way to achieve this. Of course, there are other ways to achieve abstraction in JavaScript, but for the purpose of this article, we’ll stick to using object literals to accomplish this result.
An object is declared as so:
const objectname1 = {
property1: ”String”,
property2: 100,
objectname2: { }
}
Let’s use an example to illustrate object use in object-oriented programming.
Next, we’ll attempt to create a car object inside of a land vehicle class. Instead of individually declaring the car's properties in the class, we can use an object to organize everything in one spot:
const car =
{
brand: ”Audi”,
model: “Q” + 7,
year: 2021,
dashDisplay()
{
console.log(“This is a ” + brand + ” ” + model + “ ”+ year );
}
};
const truck =
{
//truck properties.
};
car.brand;
car.model;
car.year;
car.dashDisplay;
As shown above, refactoring code with object literals makes it easier for a developer to see the essential parts of the code. It also prevents other objects, like the truck object, from accidentally accessing the properties of the car object. No changes or additions can be made quickly to the code.
JavaScript Classes
Classes in JavaScript are blueprints for creating an object. They encapsulate data and code to work on that data. In JS, they are built on prototypes, but they also have their own syntax and semantics. For example, classes can contain variables, methods and objects.
Defining a Class
To declare a class, we use the class
keyword followed by the class name and curly brackets. It is possible to declare a class without specifying the class name. Both methods of declaration are illustrated below.
One thing to note about classes is how different they are from functions. For example, they can only be called after they have been defined, unlike functions, which can be called before being defined. Therefore, calling a class before its definition will result in a reference error.
It’s also important to note that defining a class with a class name is known as a class declaration.
class Person
{
constructor(name, age, height)
{
this.name = name;
this.age = age;
this.height = height;
}
}
Further, defining a class without a name is known as a class expression.
let person = class{
constructor(name, age, height)
{
this.name = name;
this.age = age;
this.height = height;
}
sayHi()
{
console.log(`Hey, my name is ${name} and I am ${age} years old)
}
}
The constructor method used above is unique, and can only be defined once in a class using the keyword constructor. It is used to create and initialize an object with a class. Declaring a constructor is optional, as one will be made in the background for the class if one is not defined.
Inheritance Using Classes and Subclasses
It’s possible to have one class share properties with another class. In JavaScript, we create one class called the main class. The main class has all the features and functionality needed across the board, and other classes inherit from that class. The other classes are known as subclasses, and they use the extends
keyword followed by the name of the main class.
Now, let's create a Lion
class that is inherited from the Animal
class to illustrate this:
class Animal
{
const trait =
{
animal,
hunger,
speed,
sound
};
Speak()
{
let sound = trait.sound;
console.log(“This animal makes a ” + this.sound);
}
Feed(food)
{
If(trait.hunger == 0)
{
console.log("It eats its fill of " + food);
}
}
Walk(speed)
{
trait.speed = speed;
console.log(“It walks at ” + speed + ”km/h”);
}
}
class Lion extends Animal
{
trait.animal = “lion”;
trait.hunger = 0;
trait.sound = “roar”;
}
const lion1 = new Lion();
lion1.Speak();
lion1.Feed(“Deer”);
lion1.Walk(10);
By adjusting the properties of the trait object in the Lion
class and calling the Speak
, Feed
and Walk
functions. The resulting message would be the following:
This animal makes a roar.
It eats its fill of Deer.
It walks at 10km/h.
The Lion
class has inherited all the functionality and properties associated with the Animal
class and can make changes to these properties as needed. Using inheritance allows for code reusability. Also, the methods and properties of an existing class can be shared, allowing us to write shorter, more efficient code.
Polymorphism Through Method Overriding
Just as inheritances enable the sharing of properties and functions, sometimes the shared functions might need to be tweaked to suit the class inheriting these functionalities. In this case, we have to use polymorphism. It allows a common method to be implemented differently in multiple objects. Polymorphism can be achieved through a process known as method overriding.
Method overriding allows a subclass to implement the main class method differently by redefining the method in the subclass. A simple example to illustrate this is shown in the two classes below:
class Vehicle
{
Horn()
{
console.log(“This vehicle makes a sound”);
}
}
class Truck extends Vehicle
{
Horn()
{
console.log(“A truck makes a loud honking sound.”);
}
}
let transport = new Truck();
transport.Horn();
The above code will output: A truck makes a loud honking sound.
Encapsulation in JavaScript
Encapsulation in JavaScript is done using an access modifier before the variable or function name. By starting a character with a hashtag(#), we make the variable or function private in the class, hiding it from other objects that have access to it. When a variable or function is made private, it can only be accessed within the declared class.
Here’s a method and variable declaration that does this:
class Time
{
#hour = 22;
#minute=15;
#second = 05;
constructor(hour, minute, second)
{
this.#hour = hour
this.#minute = minute
this.#second = second
}
#ResetToZero()
{
this.#hour = 0;
this.#minute=0;
this.#second = 0;
console.log(`New time ${this.#hour} : ${this.#minute} : ${this.#second}`);
}
callResetToZero()
{
#ResetToZero();
}
}
class Watch
{
let time = new Time(19,30,0);
time.#hour; // this will produce an error
time.#ResetToZero(); //this will also produce an error.
}
Additionally, the only way to access a private variable or method from another class is by calling that method in a public method within the main class and using that method in the sub-class.
Conclusion
Using the pillars of object oriented programming will help make you a better programmer and allow you to write more effective code. With the OOP principles and concepts explained in this article, you can better implement object oriented programming in your JavaScript code.