Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at how to define classes with JavaScript.
Safety Checks
The JavaScript interpreter does some safety checks when instantiating classes.
this
is originally uninitialized in the derived constructor means that an error will be thrown if we try to access this
before calling super
in a subclass.
When this
is initialized, then calling super
produces a ReferenceError
since super
is already called to initialize this
.
If a constructor returns an non-object, then a TypeError
is thrown.
If a constructor returns an object explicitly, then that’s used as the result.
In this case, it doesn’t matter if this
is initialized or not.
The extends Keyword
The value that we’re extending must be a constructor.
However, null
is allowed.
For instance, we can write:
class Foo extends Bar {}
given that Bar
is a constructor.
Foo.prototype
would be Bar
in this case.
We can also write:
class Foo extends Object {}
since Object
is a constructor.
Foo.prototype
would be Object
in this case.
And we can also write:
class Foo extends null {}
Then Foo.prototype
is null
.
Referring to Base Class Properties in Methods
We can refer to base class properties in methods.
For example, if we have:
class Person {
constructor(name) {
this.name = name;
}
toString() {
return `${this.name}`;
}
}
Then we can create a subclass for Person
by writing:
class Student extends Person {
constructor(name, grade) {
super(name);
this.grade = grade;
}
toString() {
return `${super.toString()} (${this.grade})`;
}
}
We create the toString
to create a method that calls the toString
method of Person
with super.toString
.
This is done by searching for the toString
method up the prototype chain to get the toString
method and calls it.
Then the method is called if it’s found.
This is different from what we did in ES5 or earlier.
In earlier versions, we call a superclass method with the call
method.
For example, we can write:
var result = Person.prototype.toString.call(this);
With ES6 or later, as we can see, we don’t have to refer to the parent class directly.
We just use super
.
super
can be used in subclass methods and constructors.
They can’t be used in function declarations.
A method that uses super
can’t be moved.
It’s tied to the object that it’s created in.
Pros and Cons of Classes
There are some pros and cons of classes.
The class syntax makes constructors look more like classes from class-based languages.
The unconventional pattern of inheritance throws many people off.
It hides a lot of complexity with managing prototypes and constructors.
Classes are backward compatible with any current code, so no breaking change is introduced.
Subclassing is supported by the class syntax.
It’s also easier for beginners to under the class syntax instead of prototypes.
No library is required for an inheritance, which is good.
This makes them more portable.
They also provide foundations for more advanced OOP features like traits and mixins.
Classes can also be statically analyzed more easily with IDEs, text editors, and more.
However, they do hide the true nature of JavaScript’s object-oriented model.
JavaScript classes look like its own entity, but it’s actually a function.
However, because of the need for backward compatibility, JavaScrtipt classes can’t be a completely new entity.
This is a compromise to make the class syntax work with existing code.
Conclusion
The JavaScript interpreter provides us with safety checks for classes.
Also, there are pros and cons with the class syntax.