ECMAScript 2015 or more well known as ES6 is the next specification for JavaScript. ES6 brings lots of new features to JavaScript including new syntax improvements. In this post, I am going to cover the new Class syntax.

Object-Oriented Programming (OOP) can be a great way to organize your projects. Introduced with ES6, the javascript class syntax makes OOP easier.Before ES6 class were introduced, if you wanted to create a class using OOP, you had to use code like

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

    var misty = new Cat('Misty');

    console.log(misty.name); // 'Misty'

But now after the introduction of ES6, we have new reserved keyword 'Class' with a constructor statement, so the ES6 equivalent of our Cat function constructor would be the following:

// ES6 Class syntax with constructor
class Cat{
    constructor(name) {
        this.name = name;
    }
}
         
let misty = new Cat('Misty');
// Outputs 'Misty'
console.log(misty.name);  

The new syntax gives us a dedicated constructor statement that runs on object creation. Constructors are helpful for any object initialization logic.

Class declarations are not hoisted  

Function declarations are hoisted: When entering a scope, the functions that are declared in it are immediately available – independently of where the declarations happen. That means that you can call a function that is declared later:

foo(); // works, because `foo` is hoisted

function foo() {}

In contrast, class declarations are not hoisted. Therefore, a class only exists after execution reached its definition and it was evaluated. Accessing it beforehand leads to a ReferenceError:

new Foo(); // ReferenceError

class Foo {}

The reason for this limitation is that classes can have an extends clause whose value is an arbitrary expression. That expression must be evaluated in the proper “location”, its evaluation can’t be hoisted.

Methods

Let's look at adding functions.In ES5 we would had something like this:

// ES5 adding a method to the Cat prototype
Cat.prototype.walk = function() {
  console.log(this.name + ' is walking.');
}
         
var misty = new Cat('Misty');
misty.walk(); // Outputs 'Misty is walking.'

ES6 offers a more clear syntax to achieve the above goal

class Cat{
    constructor(name) {
        this.name = name;
    }
     //method of ES6 defined    
    walk() {
        console.log(this.name + ' is walking.');
    }
}
         
let misty= new Cat('Misty');
console.log(misty.name);  
// Outputs 'Misty is walking'

Static methods

Static methods are methods which are added to the class itself and are not attached to instances of the class. To create a static method, you prefix a method definition with static:

class Cat{
      constructor (name) {
        this.name = name;
      }
    
      static isCat (animal) {
        return Object.getPrototypeOf(animal).constructor.name === this.name;
      }
    }
    
    var misty= new Cat('Misty');
    
    misty.isCat; // undefined
    
    Cat.isCat(misty); // true

Get & Set

ES6 classes brings a new syntax for getters and setters on object properties.

Getters and setters in ES6 serve the same purpose that they do in other languages, including ES5. ES5 already allows getters and setters via Object.defineProperty, though they're less clean and more cumbersome to use.

Effectively, getters and setters allow you to use standard property access notation for reads and writes while still having the ability to customize how the property is retrieved and mutated without needed explicit getter and setter methods.

So lets create a get and set for our name property.

// ES6 getter and settter
class Cat{
    constructor(name) {
        this._name = name;
    }
  
    get name() {
        return this._name.toUpperCase();
    }
  
    set name(newName) {
 // validation could be checked here such as only allowing non numerical values
        this._name = newName;  
    }
  
    walk() {
        console.log(this._name + ' is walking.');
    }
}
         
let misty = new Cat('Misty');

console.log(misty.name);  
// Outputs 'MISTY'

In our class above we have a getter and setter for our name property. We use ‘_’ convention to create a backing field to store our name property. With out this every time get or set is called it would cause a stack overflow. The get would be called and which would cause the get to be called again over and over causing a infinite loop.

Something to note is that our backing field this._name is not private. Someone could still access bob._name and retrieve the property. To achieve private state on objects you would use ES6 symbol and module to create true encapsulation and private state.

Inheritance

In ES6 classes inheritance much easier.With constructor functions, there were a few manual steps that had to be taken to properly implement inheritance. Prveiosuly, in es5 we had to code for inheritance like

function Pet (name) {
      this.name = name;
    }
    
    function Cat(name, tricks) {
      // invoke the Pet constructor function passing in our newly created this object 
      // and any required parameters
      Pet.call(this, name);
    
      // add additional parameters
      this.tricks = tricks;
    }
    
    // inherit the parent's prototype functions
    Cat.prototype = Object.create(Pet.prototype);
    
    // reset our child class constructor function
    Cat.prototype.constructor = Cat;

Now with new ES6 sntax, using extends keyword we can inherit the base class, so we no longer have to manually copy the parent class's prototype functions and reset the child class's constructor.

// create parent class
    class Pet {
      constructor (name) {
        this.name = name;
      }
    }
    
    // create child class and extend our parent class
    class Cat extends Pet {
      constructor (name, tricks) {
        // invoke our parent constructor function passing in any required parameters
        super(name);
    
        this.tricks = tricks;
      }
    }

You can see the es6 syntax offers a clean syntax for prototypal inheritance. One detail you may notice is the super() keyword. The super keyword lets us call the parent object that is being inherited. It is good advice to avoid this as this can cause an even tighter coupling between your objects but there are occasions where it is appropriate to use. In this case it can be used in the constructor to assign to the super constructor.

So, our complete example code using the above explained Inheritance, Classes and methods of ES6 will be

class Pet {
    constructor(name) {
        this._name = name;
    }
  
    get name() {
        return this._name;
    }
  
    set name(newName) {
        this._name = newName;
    }
  
    walk() {
        console.log(this._name + ' is walking.');
    }
}
         
class Cat extends Pet { 
    constructor(name, activity) {
        super(name);
        this._activity = activity;
    }
  
    get PetActivity() {
        return this._activity;
    }
  
    set PetActivity(activity) {
        this._activity = activity;
    }
  
    writeEating() {
        console.log(this._name + ' is cat & she is ' + this._activity + '.');
    }
}
         
let misty = new Pet('Pet');
misty.walk();
         
let catty = new Cat('Misty', 'eating');
catty.walk();
catty.writeEating();
console.log(catty.name);

here is the working fiddle link https://jsfiddle.net/1bk6wvtz/10/

Output Image:

fiddle-output-es-classes-min.png

ES6 classes Pros and Cons

ES6 classes provide a few clear benefits:

  • They are backward-compatible with much of the current code.
  • Compared to constructors and constructor inheritance, classes make it easier for beginners to get started.
  • Subclassing is supported within the language.
  • Built-in constructors are subclassable.
  • No library for inheritance is needed, anymore; code will become more portable between frameworks.
  • They provide a foundation for advanced features in the future: traits (or mixins), immutable instances, etc.
  • They help tools that statically analyze code (IDEs, type checkers, style checkers, etc.).

Complaints about ES6 Classes

  • ES6 classes obscure the true nature of JavaScript inheritance
  • Classes provide only single inheritance
    • You can override the default result returned by the new operator, by returning an object from the constructor method of a class.
    • Due to its built-in modules and classes, ES6 makes it easier for IDEs to refactor code. Therefore, going from new to a function call will be simple. Obviously that doesn’t help you if you don’t control the code that calls your code, as is the case for libraries.Classes lock you in, due to mandatory
      If you want to instantiate a class, you are forced to use new in ES6. That means that you can’t switch from a class to a factory function without changing the call sites.