Is JS an OOP Language?

John Peters - Nov 7 '20 - - Dev Community

JS Supports both OOP and Functional Programming Styles

Summary

This article does not extoll OOP to be better than Functional programming styles. It does; however, show how quickly OOP can go wrong if a single simple rule isn't followed when talking about inheritance. It also shows how OOP and Functional Styles can co-exist.

It then discusses Composition; which, allows for polymorphic traits using properties.

Finally, it discusses the Single Responsibility Principle, where OOP and Functional styles meet. At this layer there's no difference in the two styles because good OOP winds up at Functional styles anyway.

JS OOP Syntax is the exact1 same as C#,C++ and Java

Since ES6, Javascript OOP syntax is the exact same syntax as C++, Java and C#. I know this may surprise some JavaScript folks, especially those with more than 4 years experience.

1Javascript has no types, so the OOP syntax is the exact same pattern (minus types). For Typescript, it is the same syntax.

The JavaScript pattern for inheritance is

  class Parent extends BaseClass

The C# pattern is

  class Parent:BaseClass

A JavaScript Class

class Person{
  lastName;
  firstName;
}
// typescript equivalent with type checking
class Person{
  lastName:string;
  firstName:string;
}
Enter fullscreen mode Exit fullscreen mode

Note: The exact same Behavior as above, is possible using only functions in JavaScript. In fact, after compilation of the class, it winds up as a function. The 2nd article in this series will cover that.

Both class examples of Person have a lastName and firstName property. We use them like this:

let thom = new Person();
thom.firstName = 'Thomas';
thom.lastName = 'Edison';
Enter fullscreen mode Exit fullscreen mode

New Requirement
We need an employee class, employees will have an ID only. Employees are Persons which means we can use inheritance.

A JavaScript Class Inheriting a Base Class

// works only because employee
// strictly (is-a) a person
class Employee extends Person{
 empId;
}
...

let emp = new Employee();
emp.empId = 1;
emp.firstName = 'Joseph';
emp.lastName = 'Edison';
Enter fullscreen mode Exit fullscreen mode

Hey wait a minute where did emp get the first and last name properties? Answer: From extending Person.

This concept is known as sub-classing. Here's a huge secret to being successful with sub-classing or what we call 'classical inheritance'

Do not ever sub-class or try to sub-class something that does not have a strict 'is-a' relationship. For example; a car has tires but a car 'is-not' a tire, or is a tire a car! The Tire class should never be a sub-class of Car.

This is a cardinal rule which cannot be broken and is probably the root of many OOP implementation fails.

Sub-Classing

Proper sub-classing means that the sub class 'is-a' something of the parent class. An employee 'is-a' person. So it's ok for the Employee class to extend the Person class. Sub classing is always vertical in nature when seen on an object graph.

Composition
Unlike sub-classing, there is another way to inherent intrinsic javascript types as well as our own complex types. Composition is the 'has-a' relationship. A car has tires, or a car has an engine. Properties or Parameters accomplish Composition.

// with no constructor, 
// this is a model
class Car{
 // properties are compositional
 // they are has-a relationships
 tires;
 engine;
}
// with a constructor taking parms.
class Car{
 constructor(tires,engine){

   // this.engine and this.tires
   // are implicitly defined in ES6

   this.engine = engine;
   this.tires = tires;

   // in traditional OOP 
   // this is the same syntax
   // to implement data-hiding
 }
}

// compose the car like this
let ford = new Car("GoodYear MX100", "EcoBoost 8");
// or compose like this:
let ford = new Car();
ford.tires = "GoodYear MX100";
ford.engine = "EcoBoost 8";

// It's safe to say that class or function
// properties are compositional

Enter fullscreen mode Exit fullscreen mode

Cars have tires, Cars have engines. Cars are composed of properties. Any property of a class or function is composition. It has-those properties.

We now understand 'classical inheritance' as being vertical in nature, where sub-classes extend the properties and functions of the parent.

Composition shows the object graph of has-a relationships 'horizontally' We could call this 'horizontal inheritance'. Objects may contain (as in a property) or be allowed to accept a parameter to be contained or used.

Next time you hear "Favor composition over inheritance" it simply means to prefer 'has-a' implementation. Properties and Parameters with simple or complex types achieve this.

What it doesn't mean is that sub-classing is in any way something to avoid. When a sub-class truly is-a part of it's parent class it works just fine.

Single Responsibility

For both Composition and Inheritance the single-responsibility principle must be strictly followed. Every class or function we write should do only one thing. For example, a tire class or tire function should not implement a fillTire action. Tires don't fill tires, the fillTire function does. fillTire takes in a tire as a compositional part (property) to act on.

This is slightly different than C#, Java or C++ where a fillTire interface may be in the tire class. This is due to the fact that functions (methods) must exist within the class.

The reason we don't do this in JS is because functions are first class citizens. They are equal to a class in the javascript hierarchy. Functions do not need to be contained in a class.

In Javascript, the fillTire function would be contained in the Tire.js module.

OOP and Functional Styles Meet

This is where functional programming and OOP meet, the Single Responsibility Principle (SRP).

But, but, but
The class is just syntactic sugar for the run time function that's produced. True, but who cares how the run time compiler does it? Dismissing OOP concepts because "We are functional programmers only and OOP was never needed" is a bit naïve and old-school.

Don't get me wrong, the function is larger in life than the C#, Java or C++ method syntax, due to it's true first-class citizenship. If done right the function is the most powerful construct in JavaScript.

Using Class constructs is a workable solution when done properly. Sub Classing is fine but only with true 'is-a' relationships. Composition is for 'has-a' relationships and Functions are for single responsibility actions as a primary focus. Functions can contain multiple functions but only after we've created our SRP functions first.

OOP architecture in C++ is 11 years older than the invention of JavaScript. A lot has been learned in 25 years. It's all applicable to JavaScript but only if the concepts above are fully understood.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player