Table of contents
This post is a continuation of my previous discussion on the object-oriented paradigm. This time, we'll look at three of the most popular OOP terms: encapsulation, inheritance, and polymorphism.
I have tried my best to keep it practical and straightforward, so just take a breath and jump in!
๐
Inheritance
"Like father, like son"
Consider the following class, an instance of which represents an employee
entity:
class Employee {
constructor(name, age, salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
}
Now, suppose we want a manager
entity that has all the properties of an employee
plus an additional property.
We can write the blueprint in the same manner as above, using this.<prop>
multiple times. Or, to make our lives easier, we can use the concept of inheritance.
"Inheritance allows a class (child) to inherit properties from another class (parent), promoting code reusability."
For a manager
to inherit all the properties of an employee
, we use the following syntax in the Manager class:
class Manager extends Employee {
constructor(name, age, salary) {
super(name, age, salary);
this.role = "manager";
}
}
Comments:
super
is a keyword that can be used in two ways, one of them, as shown above, is as a function.When the Manager class is instantiated, e.g.
let man = new Manager('Tee', 30, 500)
,super
calls the Employee (parent) constructor, initializing its properties. These properties are then bound to the child instance.
It is private!
Continuing the above example, suppose we don't want the salary
of an employee
to be directly accessible, ensuring that once initialized, it cannot be modified from the outside.
This requirement can be fulfilled using the concept of encapsulation.
"Encapsulation is about packing data and methods in a single unit (object), and restricting direct access to some of its components to protect the objectโs internal state and ensure controlled modifications."
class Employee {
#salary;
constructor(name, age, salary) {
this.name = name;
this.age = age;
this.#salary = salary;
}
}
const emp1 = new Employee('Prash', 39, 4000);
console.log(emp1.salary); // undefined
The #
syntax, as illustrated in the above code block, restricts direct access to the salary
property, essentially making it private. The final print statement serves as a proof.
By the way, we can define a method (getter) that returns the value of a private property. This way, if needed, one can use the returned value for other purposes without being able to mutate the property itself, e.g.
class Employee {
// same code
getSalary() {
return this.#salary;
}
}
const emp1 = new Employee('Piku', 39, 4000);
console.log(emp1.getSalary()); // 4000
Let's take a detour
Consider the following script:
function doMore(n) {
if (arguments.length == 1)
console.log(arguments[0] ** 2);
else if (arguments.length == 2)
console.log(arguments[0] + arguments[1]);
else
console.log(arguments);
}
doMore(3); // 9
doMore(3, 2); // 5
doMore(3, 20, 11); // {'0': 3, '1': 20, '2': 11}
Getting straight to the point.
arguments
is a built-in object that holds the values passed during a function call, regardless of whether parameters are specified or not. It has a length
property that holds a count of the number of arguments passed to the function. The arguments
object is structured as: { 0: arg1, 1: arg2, ... }
Observing the above function calls, we can infer that depending on the number of inputs, the function serves a different purpose, as it produces radically different outputs.
This is the core of polymorphism in OOP! ๐
Polymorphism
class Shape {
area() {return 0}
}
class Square extends Shape {
constructor(side) {
super();
this.side = side;
}
area() {return this.side ** 2}
}
var sqr1 = new Square(10);
console.log(sqr1.area()); // 100
In the above snippet, it's obvious that Square is a child of the Shape class. It inherits the area
method from Shape. But when the area
method is applied on sqr1
, an instance of the Square class, it returns a non-zero number.
"Polymorphism allows a method to act differently based on the object it is acting upon. Typically, itโs achieved through method overriding in derived classes."
In our example, the area
method specified in the Square class overrides the inherited area
method. If, for some reason, the method is not available the child class, the fallback value for the area method would be 0, inherited from the parent class.
THE END.
Immensely grateful for your time ๐
See ya!