Object Oriented Programming (OOP) refers to using self-contained pieces of code to develop applications. We call these self-contained pieces of code objects, better known as Classes in most OOP programming languages and Functions in JavaScript. We use objects as building blocks for our applications. Building applications with objects allows us to adopt some valuable techniques, namely, Inheritance (objects can inherit features from other objects), Polymorphism (objects can share the same interface—how they are accessed and used—while their underlying implementation of the interface may differ), and Encapsulation (each object is responsible for specific tasks).

We will focus on only the best two techniques for implementing OOP in JavaScript. Indeed, many techniques exist for implementing OOP in JavaScript, but rather than evaluate each, I choose to focus on the two best techniques: the best technique for creating objects with specialized functionalities (aka Encapsulation) and the best technique for reusing code (aka Inheritance). By “best” I mean the most apt, the most efficient, the most robust.

Encapsulation and Inheritance Overview

Objects can be thought of as the main actors in an application, or simply the main “things” or building blocks that do all the work. As you know by now, objects are everywhere in JavaScript since every component in JavaScript is an Object, including Functions, Strings, and Numbers. We normally use object literals or constructor functions to create objects.

Encapsulation refers to enclosing all the functionalities of an object within that object so that the object’s internal workings (its methods and properties) are hidden from the rest of the application. This allows us to abstract or localize specific set of functionalities on objects.

Inheritance refers to an object being able to inherit methods and properties from a parent object (a Class in other OOP languages, or a Function in JavaScript).

Both of these concepts, encapsulation and inheritance, are important because they allow us to build applications with reusable code, scalable architecture, and abstracted functionalities. Maintainable, scalable, efficient.

In classical languages, objects are instances of classes, and a class can inherit from
another class. JavaScript is a prototypal language, which means that objects inherit
directly from other objects.

An instance is an implementation of a Function. In simple terms, it is a copy (or “child”) of a Function or object. For example:

// Tree is a constructor function because 
// we will use new keyword to invoke it.
function Tree (typeOfTree) {} 

// bananaTree is an instance of Tree.
var bananaTree = new Tree ("banana");

When building applications, you create many objects, and there exist many ways for creating these objects: you can use the ubiquitous object literal pattern, for example:

var myObj = {name: "Richard", profession: "Developer"};

You can use the prototype pattern, adding each method and property directly on the object’s prototype. For example:

function Employee () {}

Employee.prototype.firstName = "ahmed";
Employee.prototype.lastName = "Yehia";
Employee.prototype.startDate = new Date();
Employee.prototype.signedNDA = true;
Employee.prototype.fullName = function () {
console.log (this.firstName + " " + this.lastName); 
};

var emp = new Employee () //
console.log(emp.fullName()); // ahmed yehia
console.log(emp.signedNDA); // true

You can also use the constructor pattern, a constructor function (Classes in other languages, but Functions in JavaScript). For example:

function Employee (name, profession) {
this.name = name;
this.profession = profession;
} 
var richard = new Employee ("Ahmed", "Developer")
 
console.log(richard.name); //Ahmed
console.log(richard.profession); // Developer

Class/Inheritance” describes a certain form of code organization and architecture — a way of modeling real world problem domains in our software.

For example, a series of characters that represents a word or phrase is usually called a “string”. The characters are the data. But you almost never just care about the data, you usually want to *do things* with the data, so the behaviors that can apply *to* that data (calculating its length, appending data, searching, etc.) are all designed as methods of a `String` class.

Any given string is just an instance of this class, which means that it’s a neatly collected packaging of both the character data and the functionality we can perform on it.

Let’s explore this classification process by looking at a commonly cited example. A *car* can be described as a specific implementation of a more general “class” of thing, called a *vehicle*.

We model this relationship in software with classes by defining a `Vehicle` class and a `Car` class.

The definition of `Vehicle` might include things like propulsion (engines, etc.), the ability to carry people, etc., which would all be the behaviors. What we define in `Vehicle` is all the stuff that is common to all (or most of) the different types of vehicles (the “planes, trains, and automobiles”).

It might not make sense in our software to re-define the basic essence of “ability to carry people” over and over again for each different type of vehicle. Instead, we define that capability once in `Vehicle`, and then when we define `Car`, we simply indicate that it “inherits” (or “extends”) the base definition from `Vehicle`. The definition of `Car` is said to specialize the general `Vehicle` definition.

While `Vehicle` and `Car` collectively define the behavior by way of methods, the data in an instance would be things like the unique VIN of a specific car, etc.

**And thus, classes, inheritance, and instantiation emerge.**

Another key concept with classes is “polymorphism“, which describes the idea that a general behavior from a parent class can be overridden in a child class to give it more specifics. In fact, relative polymorphism lets us reference the base behavior from the overridden behavior.

Class theory strongly suggests that a parent class and a child class share the same method name for a certain behavior, so that the child overrides the parent (differentially). As we’ll see later, doing so in your JavaScript code is opting into frustration and code brittleness.


JavaScript “Classes
Where does JavaScript fall in this regard? JS has had *some* class-like syntactic elements (like `new` and `instanceof`) for quite awhile, and more recently in ES6, some additions, like the `class` keyword (see Appendix A).

But does that mean JavaScript actually *has* classes? Plain and simple: **No.**

Since classes are a design pattern, you *can*, with quite a bit of effort (as we’ll see throughout the rest of this chapter), implement approximations for much of classical class functionality. JS tries to satisfy the extremely pervasive *desire* to design with classes by providing seemingly class-like syntax.

While we may have a syntax that looks like classes, it’s as if JavaScript mechanics are fighting against you using the *class design pattern*, because behind the curtain, the mechanisms that you build on are operating quite differently. Syntactic sugar and (extremely widely used) JS “Class” libraries go a long way toward hiding this reality from you, but sooner or later you will face the fact that the *classes* you have in other languages are not like the “classes” you’re faking in JS.

What this boils down to is that classes are an optional pattern in software design, and you have the choice to use them in JavaScript or not. Since many developers have a strong affinity to class oriented software design, we’ll spend the rest of this chapter exploring what it takes to maintain the illusion of classes with what JS provides, and the pain points we experience.


Constructor

Instances of classes are constructed by a special method of the class, usually of the same name as the class, called a *constructor*. This method’s explicit job is to initialize any information (state) the instance will need.

For example, consider this loose pseudo-code (invented syntax) for classes:

class CoolGuy {
 specialTrick = nothing

 CoolGuy( trick ) {
 specialTrick = trick
 }

 showOff() {
 output( "Here's my trick: ", specialTrick )
 }
}

Joe = new CoolGuy( "jumping rope" )
Joe.showOff() // Here's my trick: jumping rope

Notice that the `CoolGuy` class has a constructor `CoolGuy()`, which is actually what we call when we say `new CoolGuy(..)`. We get an object back (an instance of our class) from the constructor, and we can call the method `showOff()`, which prints out that particular `CoolGuy`s special trick.

The constructor of a class *belongs* to the class, almost universally with the same name as the class. Also, constructors pretty much always need to be called with `new` to let the language engine know you want to construct a *new* class instance.


Class Inheritance
In class-oriented languages, not only can you define a class which can be instantiated itself, but you can define another class that **inherits** from the first class.

The second class is often said to be a “child class” whereas the first is the “parent class“. These terms obviously come from the metaphor of parents and children, though the metaphors here are a bit stretched, as you’ll see shortly.

When a parent has a biological child, the genetic characteristics of the parent are copied into the child. Obviously, in most biological reproduction systems, there are two parents who co-equally contribute genes to the mix. But for the purposes of the metaphor, we’ll assume just one parent.

Once the child exists, he or she is separate from the parent. The child was heavily influenced by the inheritance from his or her parent, but is unique and distinct. If a child ends up with red hair, that doesn’t mean the parent’s hair *was* or automatically *becomes* red.

In a similar way, once a child class is defined, it’s separate and distinct from the parent class. The child class contains an initial copy of the behavior from the parent, but can then override any inherited behavior and even define new behavior.

It’s important to remember that we’re talking about parent and child **classes**, which aren’t physical things. This is where the metaphor of parent and child gets a little confusing, because we actually should say that a parent class is like a parent’s DNA and a child class is like a child’s DNA. We have to make (aka “instantiate“) a person out of each set of DNA to actually have a physical person to have a conversation with.

class Vehicle {
 engines = 1
 ignition() {
 output( "Turning on my engine." )
 }

 drive() {
 ignition()
 output( "Steering and moving forward!" )
 }
}

class Car inherits Vehicle {
 wheels = 4
 drive() {
 inherited:drive()
 output( "Rolling on all ", wheels, " wheels!" )
 }
}

class SpeedBoat inherits Vehicle {
 engines = 2
 ignition() {
 output( "Turning on my ", engines, " engines." )
 }

 pilot() {
 inherited:drive()
 output( "Speeding through the water with ease!" )
 }
}

**Note:** For clarity and brevity, constructors for these classes have been omitted.

We define the `Vehicle` class to assume an engine, a way to turn on the ignition, and a way to drive around. But you wouldn’t ever manufacture just a generic “vehicle”, so it’s really just an abstract concept at this point.

So then we define two specific kinds of vehicle: `Car` and `SpeedBoat`. They each inherit the general characteristics of `Vehicle`, but then they specialize the characteristics appropriately for each kind. A car needs 4 wheels, and a speed boat needs 2 engines, which means it needs extra attention to turn on the ignition of both engines.


Polymorphism

`Car` defines its own `drive()` method, which overrides the method of the same name it inherited from `Vehicle`. But then, `Car`s `drive()` method calls `inherited:drive()`, which indicates that `Car` can reference the original pre-overridden `drive()` it inherited. `SpeedBoat`s `pilot()` method also makes a reference to its inherited copy of `drive()`.

This technique is called “polymorphism”, or “virtual polymorphism”. More specifically to our current point, we’ll call it “relative polymorphism”.

Polymorphism is a much broader topic than we will exhaust here, but our current “relative” semantics refers to one particular aspect: the idea that any method can reference another method (of the same or different name) at a higher level of the inheritance hierarchy. We say “relative” because we don’t absolutely define which inheritance level (aka, class) we want to access, but rather relatively reference it by essentially saying “look one level up”.

In many languages, the keyword `super` is used, in place of this example’s `inherited:`, which leans on the idea that a “super class” is the parent/ancestor of the current class.

Another aspect of polymorphism is that a method name can have multiple definitions at different levels of the inheritance chain, and these definitions are automatically selected as appropriate when resolving which methods are being called.

We see two occurrences of that behavior in our example above: `drive()` is defined in both `Vehicle` and `Car`, and `ignition()` is defined in both `Vehicle` and `SpeedBoat`.


Multiple Inheritance

Recall our earlier discussion of parent(s) and children and DNA? We said that the metaphor was a bit weird because biologically most offspring come from two parents. If a class could inherit from two other classes, it would more closely fit the parent/child metaphor.

Some class-oriented languages allow you to specify more than one “parent” class to “inherit” from. Multiple-inheritance means that each parent class definition is copied into the child class.

On the surface, this seems like a powerful addition to class-orientation, giving us the ability to compose more functionality together. However, there are certainly some complicating questions that arise. If both parent classes provide a method called `drive()`, which version would a `drive()` reference in the child resolve to? Would you always have to manually specify which parent’s `drive()` you meant, thus losing some of the gracefulness of polymorphic inheritance?

There’s another variation, the so called “Diamond Problem”, which refers to the scenario where a child class “D” inherits from two parent classes (“B” and “C”), and each of those in turn inherits from a common “A” parent. If “A” provides a method `drive()`, and both “B” and “C” override (polymorph) that method, when `D` references `drive()`, which version should it use (`B:drive()` or `C:drive()`)?

fig2


Mixins

JavaScript’s object mechanism does not *automatically* perform copy behavior when you “inherit” or “instantiate”. Plainly, there are no “classes” in JavaScript to instantiate, only objects. And objects don’t get copied to other objects, they get *linked together*.

Since observed class behaviors in other languages imply copies, let’s examine how JS developers **fake** the *missing* copy behavior of classes in JavaScript: mixins. We’ll look at two types of “mixin”: **explicit** and **implicit**.

 

 

Advertisements