Object Oriented Programming In JavaScript – Part 3: ES6 Classes

ES6 introduced a whole host of new features into JavaScript. One of these was the class syntax. It gives us a way of defining ‘classes’ in JavaScript which is similar to more traditional Object Orientated languages such as Java. The reason I put ‘classes’ in inverted commas is because despite this new syntax, JavaScript still doesn’t have classes in the traditional sense. If you find this contradictory, don’t worry, all will be explained.

Since like pictures I feel that source code is worth 1000 words, I’m going to jump straight in with an example. The example will be the Employee and Manager example from the previous post, reimplemented using the ES6 class syntax.

class Employee {

    constructor (id, firstName, lastName, socialSecurityNumber, salary) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.socialSecurityNumber = socialSecurityNumber;
        this.salary = salary;
    }

    generatePayslip () {
        var monthlySalary = this.salary / 12;
        return "Employee ID : " + this.id
        + "\n"
        + "Name : " + this.firstName + " " + this.lastName
        + "\n"
        + "Social Security Number : " + this.socialSecurityNumber
        + "\n"
        + "Pay : $" + monthlySalary;
    }

}

class Manager extends Employee {

    constructor (id, firstName, lastName, socialSecurityNumber, salary) {
        // super refers to the parent class, in this case Employee
        // so this call to super calls the parent constructor
        super(id, firstName, lastName, socialSecurityNumber, salary);
        this.managedEmployees = [];
    }

    addManagedEmployee (employee) {
        this.managedEmployees.push(employee);
    }

    removeManagedEmployee (employee) {
        this.managedEmployees.filter(function (e) {
            return e.id !== employee.id;
        });
    }

}

// Create a new employee instance
var anEmployee = new Employee(123, 'John', 'Smith', 99090, 60000.00);

// Create a new manager instance
var aManager = new Manager(113, 'Frank', 'Pointyhair', 88454, 90000.00);

console.log(anEmployee.generatePayslip());
/*
"Employee ID : 123
Name : John Smith
Social Security Number : 99090
Pay : $5000"
*/

console.log(aManager.generatePayslip());
/*
"Employee ID : 113
Name : Frank Pointyhair
Social Security Number : 88454
Pay : $7500"
*/

The class keyword is used to create a new class. The body then consists of a series of functions. There is a ‘special’ reserved function name called ‘constructor’. This is used to denote that the function is to be used as the constructor function for the class, which means this function will be called when a new instance is created using the ‘new’ keyword.

Just as in the Employee constructor in the previous post, we set up all the instance’s properties by assigning them to ‘this’. Next we defined the generatePayslip function. Any functions defined within the body of a class will only be available to instances of the class. So to call generatePayslip we would have to create a new Employee instance, and then do anEmployee.generatePayslip().

We then come to the Manager class. Here again, we introduce yet another new keyword, ‘extends’. Extends tells JavaScript that the new class should inherit from another class. In this case we put ‘extends Employee’. I’m sure you’ve already guessed that this means that the Manager class inherits all the functionality from Employee. This means that Manager gets all of Employee’s functions, which means Manager will automatically have the generatePayslip function.

We have one final new concept coming up now, ‘super’. ‘super’ is used by a class to refer to it’s parent, so in this case super refers to the Employee class. This allows us to call Employee’s functions from within Manager. If you look at Manager’s constructor we call super(). This calls Employee’s constructor. If you remember the last post, when calling the parent’s constructor we had to make sure to call it in the context of the new Manager instance for it to work properly (we did Employee.call(this, args…)). We don’t need to do this when using super. Anytime super is used it is implicit that we want to call the function in the context of the current instance (ie ‘this’ within any function called using super will be the current instance). This is how we call the parent class constructor, but lets say Employee had another function, foo(). If we wanted to call this from within Manager, in the context of the current Manager instance we would simply do super.foo().

To complete the Manager class we add two new functions, addManagedEmployee and removeManagedEmployee. These extend the functionality given to us by Employee, and are only available to Manager, not to Employee.

Finally, we create new instances of our two new classes, and call generatePayslip on both. Note that this part of the code is identical to the same code in the previous post. This shows us that creating and using instances is identical regardless of whether we use the ES6 class syntax or just plain old constructor functions and prototypes. There is a good reason for this.

At the start of the post I teased that despite now having a class syntax, JavaScript still doesn’t have classes. The class syntax hides all the confusing use of things like Manager.prototype, and indeed the very concepts of internal and external prototypes, but under the hood they’re all still there. The class syntax is merely syntactic sugar that internally is no different from using just constructor functions and prototypes instead of classes. In fact, if you use something like Babel to compile your ES6 class code to be backwards compatible, it will produce code identical to the non class based example in the previous post.

Classes in ES6 are just a facade that hides the fact that no such thing as a class really exists in JavaScript… we’re still just creating a constructor function and adding properties to it’s prototype, which is then used to create the internal prototype of each new object instance. Given this, why was the class syntax introduced at all? In my mind there were two reasons. Firstly, it simplifies and reduces the amount of code required. Secondly, it makes OOP in JavaScript look syntactically a lot more similar to other languages (Java, PHP etc). This made it easier for people coming from a more traditional OOP language to learn JavaScript, as the prototypal inheritance concept often confused these people.

I would certainly recommend using ES6 classes over the ‘old’ way of doing OOP in JavaScript. it just makes things a little easier. Programming is hard, so anything that lightens the load is a plus in my book.

Full Series

2 comments

  1. Really enjoying these posts. For completeness, I think it would be good to include a full source of the class version, especially so as you say it should be the way to write class like code even if it’s just syntax sugar and functionally identical to the previous version.

Leave a Reply

Your email address will not be published. Required fields are marked *