ES6 Classes

Introduction

There's no doubt that JavaScript popularity has skyrocketed the last few years, and its quickly becoming the language of choice for not only client-side code, but server side as well. I had never been a huge fan of JavaScript, it just seemed too messy and unnecessarily confusing. While I still believe some of this to be true, much of it was just a misunderstanding of the language and an intolerance for a lack of certain features/syntax (i.e. traditional classes).

With the release of ES6, JavaScript seems to be moving more towards the language I personally want it to be, with the addition of traditional-style classes, generators, iterators, built-in Promises, and many other features. Personally, I believe this will ease the transition for developers coming from other languages like Java (like I did), Python, and C++. Learning JavaScript opens up a lot more possibilities to developers, allowing them to write code for just about any platform you'd want (browser-side, server-side via Node/io.js, mobile apps via React Native, and even desktops apps).

Keep an eye on the new ES6 and ES7 features, they're all there for a reason and solve some big problems for developers, like dealing with callback hell.

In this article, I'll be going through the features and caveats of ES6 classes.

ES6 Classes

So, let's get right in to it. Here are the bare essentials to create a ES6 class:

class Animal {}

var a = new Animal();

This does exactly what it looks like, it defines an empty class with no properties or methods. There are a few different ways to define an ES6 class, with the above syntax being one of them. You can also define anonymous, or unnamed classes, like so:

var Animal = class {
    constructor(name) {
        this.name = name;
    }
};

This is equivalent to anonymous classes in Java, where you define and instantiate the class at the same time.

From here, we can add a properties. In order to do that, we must define them within the constructor, as opposed to outside of it like Java requires.

class Animal {
    constructor() {
        this._name = 'cow';
    }
}

var a = new Animal();
console.log(a._name);   // Prints 'cow'

To access or modify this data, we can define getter and setter methods:

class Animal {
    constructor(n) {
        this._name = n;
    }

    get name() {
        return this._name;
    }

    set name(n) {
        this._name = n;
    }
}

var a = new Animal('cow');
console.log(a.name);    // Prints 'cow'
a.name = 'cat'
console.log(a.name);    // Prints 'cat'

As with many other languages, we can use both static and instance methods to access or manipulate class data:

class Animal {
    constructor(n) {
        this._name = n;
    }

    get name() {
        return this._name;
    }

    set name(n) {
        this._name = n;
    }

    fullName() {
        return 'holy ' + this._name;
    }

    static className() {
        return 'Animal';
    }
}

var a = new Animal('cow');
console.log(Animal.className());    // Prints 'Animal'
console.log(a.fullName());          // Prints 'holy cow'

For Java and C# developers, this should look familiar. We have the traditional methods and static methods, just like in many other languages.

So far, the features I've shown don't add too much to JavaScript that we couldn't already do before. The real usefulness of ES6 classes is realized when we use inheritance with the extends keyword. This functionality was available before, but you had to deal with the prototype and use util.inherits, which felt a bit awkward and wasn't very clear to novice JS developers. Now, we can do something like this:

class Dog extends Animal {
    constructor() {
        super('dog');
    }

    fullName() {
        return 'snoop ' + this._name;
    }

    static className() {
        return 'Dog';
    }
}

var d = new Dog();
console.log(Dog.className());   // Prints 'Dog'
console.log(d.fullName());      // Prints 'snoop dog'

This syntax and behavior should be understandable and intuitive enough for most developers to dive right in. Additionally, it should also make learning JS much easier to more novice programmers.

One caveat to watch out for is 'hoisting'. Hoisting is JavaScript's default behavior of moving declarations to the top. The difference between class declarations and function declarations is that functions are hoisted and classes are not. This means that in order to use a class, it must be defined before you use it.

var a = new Animal();    // ReferenceError!
class Animal {}

Functions, on the other hand, can be used before they are defined.

Conclusion

Although much of this functionality has always been available, I believe this is a huge step in making JS more user-friendly. Syntax and ease-of-use is a huge factor in language adoption, so this will likely propel JS even further in popularity.

What do you think about the new ES6 classes? Let us know what you think in the comments!