ES6 provided many new features for OOP, and although most of them just syntactical sugar over the existing construction pattern, but they are a step ahead of creating objects from the existing features.
I am going to show in this post why they are good pattern to use, and how they can fix many problems in the construction function pattern, and we will explain the OOP fundamentals in depth.


JavaScript OOP and prototypal inheritance in ES5

OOP in JavaScript is extremely simple, and we can explain it in these points:

  • An object in JavaScript is as simple as a collection of key-value pairs which we call them properties. Some of these values could be functions, in which case we call them methods.
  • Objects in JavaScript are dynamic which means we can add , remove, override its properties.
  • Inheritance in JavaScript is very simple as well, and it is accomplished through a special internal property called prototype.

Let us start discover how OOP works and we start with the simplest form:

Creating objects with object literal

Create an object using object literal:

var bob = {
     firstName: "Bob",
     lastName: "Smith",
     age: 30
 }

And the properties of that object will be:

states

The prototype is represented above with the property name  __proto__ . __proto__ was a property supported by some browsers, but now it is a new standard in ES6, which represents the internal property that points to the prototype object. Some books refer to __proto__ as  [[prototype]] .

Inheritance with constructor function

In order to inherit from an object in JavaScript ES3 we had to use the constructor pattern, which is described below:

var Animal = function(type, breed) {
  this.type = type;
  this.breed = breed;
  this.run = function() {
    console.log('run');
  };
};

Animal.prototype.sound = function() {
  console.log('sound');
};

var dog = new Animal('dog', 'german shepherd');

states


states

The constructor function with the new keyword works like this:

  1. It creates a new empty object (dog)
  2. It sets a property called constructor that points to the constructor function
  3. It sets dog prototype to the Animal.prototype
  4. It calls the Animal as a function, with the context of the new object


There are some remarks about this pattern:

  1. If you look at the representation of the constructor function Animal, you will see that the function is an object by itself, and that because functions in Javascript are objects.
  2. The Object has two properties: prototype and __proto__. The __proto__ is the internal property that points to the inherited prototype which is in this case the prototype of Function, and the other property prototype which is a normal property in the object that hold an object that will be the new inherited prototype for the new created object.
  3. If we call the constructor function as a function forgetting the keyword new before it, then JS will consider that we are calling a function, and the keyword this in the constructor will be referencing the global object which is the window object in the browser, which will contaminate the global object, and might introduce bugs.
  4. We see here two functions: run, sound. The run function is not defined in the prototype as the sound. When JavaScript engine create a new Animal object, it will allocate memory to create the function for each new object created, which is different from the prototype, where all objects share the same object in memory.

Using Object.create

As you saw from the previous pattern, there was so much work to just assign an object to the _proto__ property, and that unnecessary complexity was the motivation for Douglas Crockford to create the Object.create pattern.
Douglas introduced a pattern that will hide that complexity in a simpler static method on the global Object to create and add inheritance.
This pattern was introduced officially in ES5 and Object.create became part of ES5. Many developers prefer avoid using the constructor pattern with the _new
keyword, and instead using the Object.create pattern.


New OOP tools in JavaScript ES6

What ES6 provided for the OOP in JavaScript:

__proto__ and Object.setPrototypeOf

ES6 standardized the __proto__ property that was supported in some browsers. __proto__ is an accessor property (a property with getter / setter functions). But the usage of it is discouraged in favor of getPropertyOf/setPrototypeOf.
Object.setPrototypeOf is a method in the Object.prototype, which allow to change the prototype of an object. But the usage of setPrototypeOf is discouraged if you care about the performance.
Before this method, there was no way to set the prototype directly on an object. I am hoping that for future releases the performance hit will be fixed, otherwise what the use of this new method.


Classes

Classes are just syntactical sugar over constructor functions. They fixed many problems that the constructor functions had. Let us see how we can recreate Animal and dog with Class.

var Animal = class {
   constructor(type, breed) {
     this.type = type;
     this.breed = breed;
   }
   run() {
     console.log('run');
   }
   sound() {
     console.log('sound');
   }
  };
var dog = new Animal('dog', 'german shepherd');

states


states

If we dump what is in the memory, we will see that the class represented as a constructor function.
But we can list these advantages for using the keyword classes over construction:

  1. It fix the first problem mentioned above which is calling the constructor function without the “new” keyword. if we call the class as a function nothing will happen.
  2. There is no confusion of adding a function inside the constructor or in the prototype.
  3. It is readable and more clear.
  4. No need to define the prototype and add methods to it.


Sub classes with extends

Now, we can easily create the prototype chain with extends keyword as follow:

var Dog = class extends Animal {
   sound() {
     console.log('dog sound');
   }

   bark() {
     console.log('bark');
   }
};

var secondDog = new Dog('dog', 'Pit Bull');

states


states

What we can learn from the previous example:

  1. The newly created object secondDog has a prototype of Dog’s prototype, which has the prototype of Animal. It was easy to create that property chain.
  2. The class with sub-class are internally constructor functions, and the Dog has the __proto__ points to the constructor function object of Animal, and Animal object points to Function.prototype.
  3. The property prototype of Dog has __proto__ that points to Animal’s prototype.

the static keyword

ES6 provides the static keyword to define static method. Using static is cleaner and more descriptive than ES5.

// In ES6:
// define static method for the Animal 
var Animal = class {
  constructor (type, breed) {
    
  }

  static speak() {

    console.log('speak....');
  }
};
// usage of static 
Animal.speak();

// -------------------------------------
// In ES5:
// the way to do it, just add the method on the function Animal itself, because Animal is an object 
var Animal = function(breed, type) {
   .....
};
Animal.speak = function() {

};

As you see, the ES6 provides unified interface to define instance/and static method.


Conclusion

ES6 classes fixed many problems with the constructor function pattern, and it is a good choise to create / represent your objects.