Did you Inherit this property?

OOP in JavaScript - Part 2

ยท

4 min read

Did you Inherit this property?

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!

ย