ES6 Features 13: Classes
Almost a year ago I finished a series on the new features of Ecmascript 6, the next version of Javascript. At the time there were one or two features remaining that I hadn't covered, but I didn't feel that today's browsers supported them well enough for me to write a blog post on them. Today, however, that has changed, for classes at least. In this blog post I'll explain by example how classes work in ES6.
Originally, I was against the idea of having classes in javascript. After using them for a while, I've decided to change my mind. They can bring organisation to an otherwise rather cluttered project, especially since the modules syntax hasn't yet landed.
If you've you're familiar C♯, then ES6 classes will feel a little bit familiar. Here's a simple example:
"use strict";
class Bicycle
{
constructor(inPosition, inColour)
{
this.pos = inPosition;
this.colour = inColour;
this.wheelCount = 2;
this.setup();
}
setup()
{
}
update(dt)
{
}
render(context)
{
// Do rendering stuff
}
}
Very familiar (I hope). Classes in ES6 are defined using the class Tree { }
syntax, with everything belonging to that class inside a set of curly braces, just like in C♯. Because javascript isn't a typesafe language, method declarations look a bit different. Essentially they are the same as a C♯ method declaration, just with the type names taken out.
The "use strict";
at the top is important - today's browsers don't let you use classes without it. I'll omit it in later examples for sake of simplicity, but you'll always need to remember to include it when using ES6 classes.
The constructor()
method is, as you've probably guessed, the constructor of your class. Strange way of doing things, I know, but that's how it's declared. Note also that all variable initialisation is done in the constructor and not in the class body. Apparently class definitions are supposed to define an object's capabilities and not its members.
Calling a method from inside is an ES6 is easy too (see highlighted line #8), but it's important to understand what the this
variable is in this context first (I could write a whole separate blog post about this
). this
is a special variable in javascript that holds the current context. In the case of an ES6 class, it holds the current instance of the current class. This is identical to C♯, but the difference is that you'd normally never need to use this
in C♯ and it's required in ES6 - for both method access and variable access.
class Tree
{
grow(dt, rate)
{
this.classMethodA(4, dt, this.someVariable);
}
// ...
}
White noise
Update: It turns out that ES6 does indeed support static methods (but not variables I don't think) natively via the static keyword
. Here's an example:
class Tree
{
constructor()
{
this.something = Tree.doComplicatedStuff();
this.somethingElse = this.constructor.doComplicatedStuff();
}
static doComplicatedStuff()
{
// ...!
}
}
Native static methods can be called in two ways (highlighted above). One is practically the same as the C♯ way of doing things, and the other is useful if for whatever reason you don't have the name of your own class handy.
Original sectional text
class NoiseGenerator
{
constructor()
{
// ...!
}
GetNoise(amount)
{
// ...!
}
}
Let's pretend that we want all our noise generated with our class to use the same seedable random number generator. How about rand = new MyPRNG();
? Or window.rand = new MyPRNG();
? Or even this.rand = new MyPRNG()
? Unfortunately, all of these methods have at least one problem with them (if you know what's wrong with them, comment down below!). Don't despair though, because we can exploit the fact that classes themselves are objects - and aren't read-only. With this knowledge, we can do something like this:
NoiseGenerator.rand = new MyPRNG(someSeed);
Remember to put the above _after_ the class definition - ES6 classes are a little bit like C++ classes in that they don't exist until the interpreter has executed them (unlike regular old functions). Then in the body of a method, you can access it with something like `NoiseGenerator.rand.nextInt(0, 10);`.
Too many classes
ES6 classes do infact support inheritance under the guise of sub classing. A good example is worth a thousand words I think:
class Vehicle
{
constructor()
{
// ...
}
move()
{
console.log("Moving vehicle...");
}
start() { console.log("Starting..."); }
stop() { console.log("Stopping."); }
}
class Train extends Vehicle
{
move()
{
super.move();
console.log("Moving train...");
}
}
As demonstrated in the example above, classes can inherit from one another with the extends
keyword instead of C♯'s colon. The super
word replaces the functionality of C♯'s base
keyword too. Other than that, there really isn't a lot more to say about inheritance in ES6 besides the fact that almost everything not described works as you'd expect it to in C♯.
That concludes my whirlwind tour of classes in ES6. If I explained in detail every little feature, you'd be here all week reading about it (and I'd be here for the better part of a month writing this post!). ES6 classes also support getters and setters, overriding the default constructor, and more.