OOP in the age of ES6

Published on

Recently, I have become more of a “Ruby/Bash/Haskell” guy, but JavaScript will always remain one of my favorite languages, and I couldn’t be happier when I saw the new new upcoming ES6 standard.

ES6 is the new sexy ECMAScript standard that brings a lot of goodies to the JavaScript world. One of the new features I am really looking forward to is the new classical OOP system.

If you are familiar with JavaScript, you probably know that that it uses an alternative version of Object Orientation that relies on object prototypes. While in theory the prototypical nature of JavaScript is superior to the classical version, in the sense that it can simulate the later, in practice it is often confusing and a common source of bugs.

The new OOP system on the other hand is intuitive and comparable to the system implemented in Ruby, Python or Scala. This article will demonstrate some of the awesome things that you can soon use in your daily JavaScript development.

Constructing classes

Finally the useless reserved word class can shine. The new OOP system uses it to define new classes. Here is an example:

class Dog {
  constructor(name) {
    this.name = name;
  }

  bark() {
    console.log("wuf! wuf!");
  }
}

var leo = new Dog("Leo");
leo.bark();

At the first glance, we can instantly recognize the intuitiveness of the above construct. It defines a Dog class with a constructor that takes it name, and an instance method that let’s our dogs to bark.

Notice also that the methods don’t have a function keyword and that there is no prototype word anywhere in the source file. Just as a reminder of the old days, I will rewrite the above class to the current ES5 format:

function Dog(name) {
  this.name = name;
}

Dog.prototype.bark = function() {
  console.log("wuf! wuf!");
};

var leo = new Dog("Leo");
leo.bark();

You can argue that this version is shorter, but it is definitely weirder no matter how you look at it.

Inheritance

If you were amazed with the new system, prepare yourself for even more. Inheritance was always one of the most confusing parts of prototypical OOP.

The above questions always boggled my mind. I learned them when I needed them, but after a week or two I completely forgot them. Luckily for me, the new system uses extends and super.

Let’s extend the above Dog class to a subtype of dogs, for example Labradors:

class Labrador extends Dog {
  constructor(name) {
    super(name);
  }

  playWithKids() {
    console.log("playing with kids! wuf! wuf!")
  }
}

var leo = new Labrador("Leo");
leo.playWithKids();

But how do you redefine a method? Let’s say for the sake of the following example that Labradors have a different kind of bark that instead of wuf! wuf! says wuf! wuf! woof!. Here is how we can do it:

class Labrador extends Dog {
  constructor(name) {
    super(name);
  }

  bark() {
    console.log("wuf! wuf!");
    console.log("woof!");
  }

  playWithKids() {
    console.log("playing with kids! wuf! wuf!")
  }
}

var leo = new Labrador("Leo");
leo.bark();

Pretty simple. We can even use the definition from the parent class by doing the following:

class Labrador extends Dog {
  constructor(name) {
    super(name);
  }

  bark() {
    super.bark();
    console.log("woof!");
  }

  playWithKids() {
    console.log("playing with kids! wuf! wuf!")
  }
}

var leo = new Labrador("Leo");
leo.bark();

That was again, blazingly simple. I don’t even know how to do that in plain old JavaScript.

Getters

There is one more feature that I want to write about, the new getter syntax. Let’s start with an example User class:

class User {

  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName  = lastName;
    this.age       = age;
  }

}

var user = new User("Igor", "Sarcevic", 24);

Now, let’s say there is a need to get the full name of the user. We can define a method called fullName like this:

class User {

  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName  = lastName;
    this.age       = age;
  }

  fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

var user = new User("Igor", "Sarcevic", 24);

console.log(user.fullName());

Note: I used the sexy new string template syntax, go look it up, you won’t regret it. :D

The fullName method is simple but it can bother you that you must append the function invoking brackets user.fullName() every time you need to know the full name of the user. Luckily, we can use getters:

class User {

  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName  = lastName;
    this.age       = age;
  }

  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

var user = new User("Igor", "Sarcevic", 24);

console.log(user.fullName);

In the above example pay attention to the addition of the get keyword and the removal of the brackets when the getter was invoked user.fullName.

Final words

I can only say that I fell in love with the new OOP style. Finally, JavaScript can be as expressive as the other languages in its category.

But it makes me wonder what is the future of CoffeeScript?