Object-oriented Programming in JavaScript
Tags: beginners, javascript, oop, webdev
Published: 2021-06-16 08:37:07

In programming, there is a technique for writing code called **object-oriented programming**. It's a methodology for code abstraction and organization where the code written embodies the traits of real-world objects (like a car, a house or even a person) and their related features. Although each programming languages differ in the implementation of **OOP**, the concept remains the same.

### Encapsulation

In object-oriented programming, programs are divided into pieces, and each piece is responsible for managing its state. The way a piece of program works is local and encapsulated to that piece. This is known as *encapsulation*.

Different pieces of the program interact with each other through *interfaces* --- functions or bindings that provide interaction, and useful functionalities at an abstract level, hiding their precise implementation. Such programs are modelled after **objects**, again, like a car, a house or a person.

An object consists of properties (**attributes** and **methods**), properties that are part of an object, and only work within that object are **private**. Others, that part of the object, but interact with outside code are called **public**.

In JavaScript, there is no distinct way to identify private, and public properties, and to prevent outside code from accessing the private properties. One common way is to describe properties that are private or public in the documentation and comments. Another way is to use an underscore (_) at the start of property names to indicate that they are private.

### Method

Methods are property names in an object that hold function values.

For instance, a simple method:

```javascript
const pet = {};
pet.bark = (bark) => {
    console.log(`My dog says '${bark}'`);
}

pet.bark("Woof") // → My dog says 'woof'
```

Methods are called on object to perform certain tasks. When a function is invoked as a method, the binding `this` points to the object that the method was called on.

For instance:

```javascript
function speak(line) {
    console.log(`The ${this.position} person says '${line}'`);
}

const firstHomie = {position: "first", speak};
const secondHomie = {position: "second", speak};

firstHomie.speak("Yo man, wats happenin?");
// → The first person says 'Yo man, wats happenin?'

secondHomie.speak("All good dawg!");
// → The second person says 'All good dawg!'
```

The `this` can be called using a function method called `call`. The `call` method takes the value `this` as its first argument, other arguments are treated as normal parameters.

```javascript
speak.call(secondHomie, "Good to know."); // → The second person says 'Good to know.'
```



> <small><b>NOTE:</b></small>
>
> In JavaScript, the "this" always binds or points to the object, and can be used to reference the object.

Regular function defined with the `function` keyword can't  refer to the `this` of a wrapping scope. such a function can only use its own `this` binding. Arrow functions don't work in the same way. An arrow function is able to access the `this` binding of the scope around it.

for instance, reference `this` from inside a local function:

```javascript
/* Using normal function */
function normalize () { // → wrapping scope
    console.log(this.coords.map(function(n){
        n / this.length
    }));
}
normalize.call({coords: [0, 2, 3], length: 5});
// → Undefinded values [ undefined, undefined, undefined ]

/** Using arrow function **/
function normalize () {
    console.log(this.coords.map(n => n / this.length));
}
normalize.call({coords: [0, 2, 3], length: 5});
// → [0, 0.4, 0.6]
```

### Prototypes

In JavaScript, most objecst can inherit properties from a parent object or a prototype. When an object is requested to access a property it does not have, it'll look into its prototype, if that prototype doesn't have it, then the prototype's prototype will be checked and so till it gets to the ancestor prototype.

```javascript
let emptyObject = {};
console.log(emptyObject.toString());
// → [object Object]
```

In the above, the object is able to access a method that is not part of its property, but part of a fallback prototype that most object inherit from -- the ancestral object prototype, `Object.protoptype`.

You can check the prototype of an object using the **object constructor**'s `getProtoypeOf` method:

```javascript
//...

console.log(Object.getPrototypeOf(emptyobject));
// → {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ,…}
```

The `getProtoypeOf` method returns the ancestral prototype properties. `Object.prototype` provides a few default methods, like `toString()`, that shows up in all object.

Some JavaScript object don't inherit from `Object.prototype` as their prototype, but from another object that provides a set of default values. Date inherit from `Date.prototype`, arrays from `Array.prototype`, and functions from `Function.prototype`.

You can use the `create` method from the **object constructor** to create an object with its unique prototype.

```javascript
let protoMouse = {
    speak(line) {
      console.log(`The ${this.type}Mouse says ${line}`);
  }
}

let dangerMouse = Object.create(protoMouse);
dangerMouse.type = "DANGER";
dangermouse.speak("Pooww!")
// → The DANGER mouse says Poow!
```

From the code above, the `dangerMouse` object has a default property of `speak` from its fallback object `protoMouse` and a property of `type` that applies only to itself. The  `protoMouse` object can be used as a container for all mice. You could have "ninja mouse", "nerdy mouse", "tech mouse" and so on. Each mouse object can implement its property but all share the same prototype, `protoMouse`.

### JavaScript Classes

Before the *class template* was introduced in JavaScript, the language used a prototype in implementing OOP classes.

A class is an OOP concept for defining the properties (methods and attributes) of an object in a structured manner. It's the blueprint of an object. Objects derived classes are an **instance** of that class.

Prototypes can be used for defining properties from which all instances of a class can inherit (share properties). Dissimilar or different properties per instance, like type, have to be defined in the object.

To create an instance of a class, you first create an object that inherits from the proper prototype. The object has to have the properties that instances of that class are supposed to have. That is what **constructor** functions do.

```javascript
//...

function makeMouse(type) {
    let mouse = Object.create(protoMouse);
    mouse.type = type;
    return mouse;
}

// Instance of 'makeMouse' class
let ninjaMouse = makeMouse("Ninja");

ninjaMouse.speak("Haiiyahh!");
// → The NinjaMouse says Haiiyahh!
```

The code above is one way of doing it, but there is an easier way: using the `new` keyword.

When a function is prepended with the `new` keyword, it creates and automatically returns an empty object that is bounded to the `this` keyword. The object has a prototype property derived from `Object.prototype`.

Let's create a different class this time:

```JavaScript
function Person(first, last, age, eye) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eye;
}

// All instances will share this property
Person.prototype.speak = functin(line) {
    console.log(`${this.firstName} says '${line}'`);
}

// An instance of the 'Person' class
let teacher = new Person("Romeo", "Peter", 22, "black");
let student =  new Person("Jane", "Doe", 25, "brown");

console.log(teacher.name); // → Romeo
console.log(student.name); // → Jane

teacher.speak("hello world!"); // → Romeo says 'hello world!'
student.speak("hello!"); // → Jane says 'hello!
```

 ><small><b>NOTE:</b></small>
 >
 >It is considered good practice to name constructor functions with an upper-case first letter.

Because constructors are functions, the actual prototype of the function is `Function.prototype.`

### Class template

A class template is a constructor function with a prototype property. It allows for a much simpler way of writing classes in JavaScript. The feature is part of the ES2015 update to JavaScript.

```javascript
class Person {
    constructor(first, last, age, eye) {
        this.firstName = first;
      this.lastName = last;
      this.age = age;
      this.eyeColor = eye;
    }

    speak(line) {
        console.log(`${this.firstName} says '${line}'`);
    }
}

// Instances of 'Person' class
let teacher = new Person("Romeo", "Peter", 22, "black");

teacher.speak("hello world!"); // → Romeo says 'hello world!'
```

The `class` keyword is used to start or declare the class, it's followed by two curly braces `{}`. you can declare any number of method within the class that'll be part of the prototype, but the constructor is special and must come first. The constructor method is a construction function that will be bounded to the class name.

><small><b>NOTE:</b></small>
>
>It is considered good practice to name class template with an upper-case first letter.

You can compare the previous class declaration that used a function to this current, one and you'll see that they're similar. Using the class template is a simpler way to write read classes.

Although class template can only hold methods (function values) for now, it is a better approach to using classes. A future update to JavaScript might allow for other values to be stored within class templates.

### Polymorphism

Polymorphism means "many forms."

In computer programming, polymorphism refers to data or object that can be used or processed in more than one form. This is a key part of OOP because it allows instances of a class to be any form as long as the expected interfaces or data types are provided.

For instance, we described what form a **person** can  by declaring the `Person` class. Consequently, a person can be a **Father**, **Mother**, **Daughter** or **Son**.

```javascript
// ...

// Instances of 'Person' in more than one form
let father = new Person("John", "Doe", 30, "black");
let Mother = new Person("Jane", "Doe", 25, "brown");
let daughter new Person("Gill", "Doe", 3, "black");
let son = new Person("Jack", "Doe", 3, "brown");
```



Another example, although more technical, is the JavaScript `String()` method that converts a value to a string. It is a polymorphic code that expects a certain interface to function as it should -- convert a value to a string.

When a `String()` method is called on an object, it'll calls the `toString()` method on that object and then converts it to a string. the method (`String()`) expect the object to have the `toString()` method as an interface.

It's possible to overwrite the `toString()` method in the prototype. Let's do that by creating the string to be returned by the `String()` method.

```javascript
// ...

Person.prototype.toString = function() {
    return `Teacher's name is ${this.firstName}.`;
}

console.log(String(teacher)); // → Teacher's name is Romeo.
```

Polymorphic code can work with data values of different forms, as long they provide the data types or interfaces required.



### Getters, Setters and Static

*Getters* and *setters* allow you to read and write to an object expression or class declaration. These are properties that have hidden method calls.

You define a getter by using the keyword `get` in front of a method in an object expression or class declaration.

For instance, a class for getting varying sizes:

```javascript
// Object expression
let varyingSize = {
    get size() {
        return Math.floor(Math.random() * 100);
    }
}
console.log(varySize.size) // → 12

//-----------------------------------

// Class declaration
class VarifyingSize {
    get size() {
        return Math.floor(Math.random() * 100);
    }
}
let size = new verifyingSize();
console.log(size.size); // → 61
```

from the code above, when you read the object's or class' *size* property, it calls the associated method. Similarly, you can write into an object or class by defining a setter.

For instance, a temperature class that sets to Fahrenheit:

```javascript
class Temperature {
    constructor(celsius) {
        this.celsius = celsius;
    }

    get fahrenheit() {
        return this.celsius * 1.8 + 32;
    }

    set fahrenheit(value) {
       this.celsius = (value - 32) / 1.8;
    }
}

let temp = new Temperature(40);

// Get
console.log(temp.farenheit); // → 104

// Set
temp.fahrenheit = 86;
console.log(temp.celcius) // → 30
```



*Static* methods, when set, are attached (stored implicitly) to the class constructor and don't have access to the class instances. That means they are methods set for a class and not for the instance of that class. Such a method can be used to provide additional ways of creating instances. You define a static method by using the `static` keyword in front of the method.

```javascript
class Temperature {
  //...

    // Store on the class constructore
    static fromFahrenheit(value) {
        return new Tempareture((value 32) / 1.8);
    }
}

// Create temperature using degrees Fahrenheit
Tempareture.fromFahrenheit(100);
// → Temperature {celsius: 37.77777777777778}
```



### Inheritance

Inheritance in OOP is when a class extends another class.

When you inherit from a class, you create new functionalities and features on top of the existing one.

```javascript
// Parent or super class
class Animal {
    constrcutor(name) {
        this.name = name;
        this.speed = 0;
    }

    run(speed) {
        this.speed = speed;
        console.log(`${this.name} runs with speed ${this.speed}.`);
    }

    stop() {
        this.speed = 0;
      console.log(`${this.name} stands still.`);
    }
}

//...
```

The above code is a generic class for animals. A generic animal like a horse can run and stop. To create a horse object, the object would have to extend the *Animal* class. The `extends` keyword is used to achieve that. The keyword `extends` tells the class not to directly derive from the default `Object.prototype` but from a class

```javascript
class Horse extends Animal {
    hide () {
        alert(`${this.name} hides!`);
    }
}

let horse = new Horse("Black Stallion");
horse.run(120) // → Black Stallion runs with speed 120.
horse.hide("neigh") // → Black stands hides!.
horse.stop() // → Black stands still.
```

JavaScript's prototype makes it possible to derived properties from one class to another. The top class knows as the *Parent* class, shares its properties with the bottom, known as the *child* class. The child class can define its properties, like a method.

><small><b>NOTE:</b></small>
>
>**Any expression is allowed after** `extends`
>
>Class syntax allows to specify not just a class, but any expression after `extends`.
>
>For instance, a function call that generates the parent class:
>
>```javascript
>function f(phrase) {
>return class {
>sayHi() { alert(phrase); }
>};
>}
>
>class User extends f("Hello") {}
>
>new User().sayHi(); // Hello
>```
>
>Here `class User` inherits from the result of `f("Hello")`.
>
>That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them.
>
><small>Source: [JavascriptInfo](https://javascript.info)</small>

By default, all methods not specified in the child class are inherited from the parent class. For instance, the `stop()` method in the previous example is derived from the parent class. If the same method is specified in the child class it'll overwrite the parent's method. Properties in the child class should only extend or build on top of the parent class. To avoid overwriting methods, a child class should call parent class properties (methods and constructor) with the `super` keyword.

For instance, the *horse* will autohide when stopped.

```javascript
class Horse extends Animal {
    hide () {
        alert(`${this.name} hides!`);
    }

    stop() { // Child class method. Does not overwrite parent
        super.stop(); // Call parent 'stop()' method
        this.hide(); // hide
    }
}
```

The *horse* class above has a stop method that calls the parent's stop method underneath in the process.

Classes that extend another class with no constructor method automatically generate an "empty" constructor. If no explicit constructor method is written, it calls the parent constructor and passes all the arguments in.

```javascript
class Horse extends Animal {
    // generated for extending classes without own constructors
    constructor(...args) {
        super(...args)
    }
}
```

To add a custom constructor to child classes, the constructor must call `super()` before using `this`. This is because the derived constructor can't access the object for `this` if the parent constructor is not called first.

```javascript
class Horse extends Animal {
    constructor(name, sound) {
        super(name);
        this.sound = sound;
    }

    //...
}

sound() {
    console.log(`The ${this.name} ${this.sound}'s.`)
}

let horse  = new Horse("Black Stallion", "neigh")

console.log(horse.name) // → Black Stallion
horse.sound() // → The Black Stallion neigh's.
```

Inheritance is a fundamental part of object-oriented programming. It allows building on top of existing data. However, unlike encapsulation and polymorphism that allow for code separation into pieces, thus reducing the overall entanglement, inheritance link and tie code together, thus increasing the tangle. When inheriting from class, knowing when to use it is just as important as how to use it.

### Summary

A recap of what we've covered so far.

Object-oriented programming is a methodology  for code organization  by representing data objects.

Encapsulation allows pieces of code to manage their state, and interact with other code through an interface.

In JavaScript, properties that operate within an object are *private* while properties that interact with outside code are *public*.

There are two ways to distinguish public and private properties:

* Specify in documentation public and private properties.
* Use underscore _ in front of the property that is private.

Prototypes are fallback objects that an object can inherit from. Most built-in objects inherit from the ancestral `Object.prototype` object.

Classes are the blueprint for an object. Objects derived from classes are *instances* of the class.

The class template was introduced in ES2015 and is a constructor function with a prototype property. It allows for a simpler way of describing classes

Polymorphism allows for objects to be used in more than one way.

Getters & setters allow to read and write to an object or class declaration.

Inheritance allows for an extension of classes. The class that extends to another class is known as the *child* class and the class that is extended from is known as the *parent* class.