A Guide To Object-oriented Programming For Javascript Newbies

A Guide To Object-oriented Programming For Javascript Newbies

If you are quite new to coding with javascript (or coding as a whole), one word I believe you might have heard often been resounded in the tech-sphere has to be Object-Oriented Programming or OOP. For newbies, it is often intimidating seeing lots of folks toss jargon like that around, but I promise you it is not as intimidating as at first glance if it is simplistically taught.

This is the aim of this article, I would seek to explain the concept of OOP as simply as possible so as to make it understandable for people new to programming.

Before delving into what Object-Oriented Programming is, let’s first of all understand the concepts of objects in programming. In Javascript, Objects are one of the data types but unlike the primitive data types, the object data type isn’t bound to a single expression but rather it is bound to keyed collections of data. It is created with braces enclosing a list of properties or key:value pairs.

let player = {
    name: 'Kun Agüero',
    age: 33,
    clubs: ['Independiente', 'Atletico Madrid', 'Manchester City', 'Barcelona'],
    intro: function(){
        return `I am ${this.name} and I play for ${this.clubs[this.clubs.length - 1]}.`
    }
}

Code Snippet I: General Syntax for Objects

Each property is a key:value pair; the keys are called the property name and they must be a string while their corresponding values can take the form of any data type, even an object. The object properties can be accessed with either of two methods, the first and most common is the Dot Notation and the second is the Bracket Notation. We used the dot notation in the example above, it involves using the object’s name followed by a dot then the property name to access the object’s property. Objects can be created in three ways;

  1. Via the Object literal syntax: This is the most common method and the one we used in our code snippet above.
  2. Via the Object Constructor: This method involves using the inbuilt javascript object constructor, Object(). This is used in conjunction with the ‘new’ keyword.
  3. Via the use of Constructor Functions: A constructor function is basically a function used to create an object. It is a function that takes in arguments, the arguments then go on to be the values of the object's properties. This method is the template for the creation of objects in OOP as it allows for the creation of multiple instances of an object, a feature that is a shortcoming of the first two methods.
function Player (name, age, clubs){
    this.name = name;
    this.age = age;
    this.clubs = clubs;
}

Player.prototype.intro = function(){
    return `I am ${this.name} and I play for ${this.clubs[this.clubs.length - 1]}.`
}

Code Snippet II: Syntax of Constructor Functions

It is considered good practice to always capitalize the first letter of your constructor function name. The keyword this used in the function refers to the object itself. Hence when you want to access the object properties, you can go on to use the dot notation as we have earlier looked at. To then create object instances of the constructor function, the new keyword is used.

const aguero = new Player('Kun Agüero', 33, ['Independiente', 'Atletico Madrid', 'Manchester City', 'Barcelona']);
const mbappe = new Player('Kylian Mbappé', 22, ['Monaco', 'Paris Saint-Germain']);
const dzeko = new Player('Edin Džeko', 35, ['Wolfsburg', 'Manchester City', 'Roma', 'Inter Milan']);

Code Snippet III: Instances of the Player Constructor Function

In the above code snippet, three objects are created using the same constructor function. These objects are all unique but also quite similar, they can have the same properties and also have more properties added to or removed from them.

const messi = new Player('Lionel Messi', 34, ['Barcelona', 'Paris Saint-Germain'])
messi.worldBest = true;

console.log(messi.worldBest) //true

Code Snippet IV: Addition of property to object instance of Player function

In the example above, we see that the new object that was created had similar properties to the others with an additional worldBest property

Let us now look at Object-Oriented Programming proper.

Object-Oriented Programming is a programming language paradigm based on the concept of “objects” i.e. creating an abstraction to hold complex data structures along with some methods that act on the data structures. A few people would simplistically say it tries to mimic how the real world works. Take, for example, our Player constructor function and its instances, in a way they mimic a few details of the real-life football players which they are modelled after and the intro function could serve as a basic introduction they could possibly say.

To understand OOP better, one thing we would look at are its concepts often referred to as the Four Pillars of Object-Oriented Programming. They are Abstraction, Encapsulation, Inheritance and Polymorphism. They are software design principles that help you write clean Object-Orientated code.

1. Abstraction

To abstract something means to hide the implementation details of something. In other words, it hides internal irrelevant details and shows only operations relevant for the other objects. This would allow the user to implement more complex logic on top of the provided abstraction without understanding or even thinking about all the hidden complexity. We can liken the processes that lead to turning on a car to what abstraction means, for instance, we know that if we want to start a car traditionally with a car key, we just have to put the key in the ignition and turn it in the right manner under ideal circumstances the car will spring to life, but from the instant, we turn the key in the ignition and when the car comes to life, certain processes took place but it isn’t really our business to know all the details of those processes. Abstraction, therefore, makes the implementation of a complex application a lot easier.

2. Encapsulation

Encapsulation means the action of enclosing something in or as if in a capsule. The principle of encapsulation entails that each object should control its own state i.e. all the properties and methods of an object can be kept private and safe from interference by other objects. In each object, we can have both private and public variables and methods. Private variables and methods cannot be called or used by other objects, whereas public ones can. To explain this better, let’s use the example of a car. Say we get a car and we want to transform it, we take it to a custom body shop to customise it. The car is an instance of the Car constructor and the people working on it are instances of the Human constructor, when the car returns back it might look totally transformed but certainly not all the original features of the car would have been done away with it as some features of the car would be inalienable to it.

3. Inheritance

Inheritance is the ability of an object to acquire some/all properties of another object. It is a mechanism that allows us to create a new Constructor function from an already existing one, what this would mean is that the new constructor would be a child of the previous function and get to inherit all the properties and methods of its parent. The child constructor function can use all the properties of its parent and implement its own. For example, imagine we are storing data for people in a small town and we want to classify them based on their professions. We would first create a Person constructor function which would have properties and methods that are general to each person, we then create an Unemployed, SelfEmployed and Employed constructors as a child of the Person constructor, the Employed and SelfEmployed functions can then go on to have other children constructor functions to represent certain professions and occupation.

4. Polymorphism

Polymorphism comes from the Greek word for “many shapes”. This refers to the condition of occurring in several different forms. Polymorphism gives us a way to use an object just like its parent but keeping its own methods. It does this by inheriting a method to be reused from its parent which it then implements in its own version. For example, in line with code snippet II, we can make variations to the intro method for a particular object instance to execute it in its own unique way.

messi.intro = function(best){
    best = this.worldBest;
    if(best){
        return `I am ${this.name} and I play for ${this.clubs[this.clubs.length - 1]} and I am currently the best football player in the world.`
    }else{
        return `I am ${this.name} and I play for ${this.clubs[this.clubs.length - 1]}.`
    }
}

Code Snippet V: Example of Polymorphism

Ways to write Object-Oriented Programming

1. Using Constructor Functions

Constructor functions are initializers of objects, just like we saw in the second code snippet. You could simplistically say that they are functions that contain the this keyword.

function Car(model, year, reg_no){
    this.model = model;
    this.year = year;
    this.reg_no = reg_no;

    this.age = function(){
        let date = new Date();
        let age = date.getFullYear() - this.year;
        return `It's ${age} years old.`
    }
}

Car.prototype.producedOn = function(){
    return `The ${this.model} was created in ${this.year}.`
}

let chevy = new Car('Chevrolet-T39', 2015, 'CHE-2015-39')

Code Snippet VI: Syntax of Constructor Function

You can also add more methods and attributes to an existing constructor function, you can do this with the prototype property.

2. Using Class Syntax

Classes were not originally in Javascript but were included in 2015, they are just syntactic sugar i.e. they don’t add anything to the code functional wise. They are just an easier way to write the constructor functions.

class Car{
    constructor(model, year, reg_no){
        this.model = model;
        this.year = year;
        this.reg_no = reg_no;
    }

    age(){
        let date = new Date();
        let age = date.getFullYear() - this.year;
        return `It's ${age} years old.`
    }

    producedOn(){
        return `The ${this.model} was created in ${this.year}.`
    }
}

let chevy = new Car('Chevrolet-T39', 2015, 'CHE-2015-39')

Code Snippet VII: Syntax for Classes

Instances of Classes are created the same way instances of Constructor functions are used, with the new keyword. This method is the most common and you would find literally almost everyone using Classes when it comes to OOP.

3. Using Objects Linking to Other Objects(OLOO)

OLOO was coined and popularized by Kyle Simpson. In OLOO, you define the blueprint as a normal object. You then use a method (often named init, but that isn’t required in the way constructor is to a Class) to initialize the instance.

const Human = {
    init(firstName, lastName){
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Code Snippet VIII: Syntax for OLOO

You use Object.create to create an instance. After creating the instance, you need to run your init function.

const kyle = Object.create(Human)
kyle.init('Kyle', 'Simpson');

console.log(kyle.firstName) //Kyle
console.log(kyle.lastName) //Simpson

Code Snippet IX: Instancing OLOO Blueprint

You can chain init after Object.create if you turned this inside init.

const Human = {
    init(firstName, lastName){
        this.firstName = firstName;
        this.lastName = lastName;
        this.sayHello =  function(){
            return `Hello, I am ${this.firstName}.`
        }

        return this
    }
}

const kyle = Object.create(Human).init('Kyle', 'Simpson')
console.log(kyle.firstName) //Kyle
console.log(kyle.lastName) //Simpson

Code Snippet X: Instancing OLOO Blueprint 2

4. Using Factory Functions Factory functions are functions that return an object. You can return any object. You can even return a Class instance or OLOO instance — and it’ll still be a valid Factory function.

function Car(model, year, reg_no){
    return {
        model,
        year,
        reg_no,
        producedOn(){
            return `The ${this.model} was created in ${this.year}.`
        }
    }
}

const chevy = Car('Chevrolet-T39', 2015, 'CHE-2015-T39');
console.log(chevy.model) //Chevrolet-T39
console.log(chevy.year) //2015

Code Snippet XI: Creating Factory Functions

You don’t need new to create instances with Factory functions. You simply call the function.


Conclusion

We have finally come to the end of this article. I know that OOP can look quite intimidating for first-timers but I want you to know that most people who understand perfectly well and use it often did not just learn it in one day, it took time for them to read, assimilate and practice it. I do not expect the Javascript newbie to understand all of this in one read but I hope this article would help lay a foundation for you in grasping Object-Oriented Programming and its concepts and how to use it.

Thank you for reading till the end.