Keywords super
and extends
are integral parts of Javascript's ES6 subclass syntax, but super
's role can seem mysterious. To get a better understanding of how they work, let's start with an example of inheritance in pseudoclassical ES6 pattern:
class Bicycle {
constructor(brand, color) {
this.brand = brand;
this.color = color;
}
describe() {
return (`This bicycle is a ${this.color} ${this.brand}.`);
}
gearing(chainRings, cogs) {
this.chainRings = chainRings;
this.cogs = cogs;
this.speeds = this.cogs * this.chainRings;
if (this.speeds > 1) {
return (`This ${this.brand} is a ${this.speeds}-speed.`);
}
if (this.speeds === 1) {
return (`This ${this.brand} is a single-speed.`);
}
}
}
const pug = new Bicycle("Peugeot", "red");
console.log(pug.describe()); /* This bicycle is a
red Peugeot. */
In the example above, the Bicycle
class has a constructor function to create a Bicycle
, and a method, gearing
, to report its gearing. Note the class
keyword, and capitalization of the class name, Bicycle
, both of which are important components of this instantiation pattern. A new instance of a Bicycle
is created with the keyword new
.
Now, on to the subclass business. Let's create a subclass Fixie
that takes on Bicycle
's properties.
class Fixie extends Bicycle {
constructor(brand, color) {
this.chainRings = 1;
this.cogs = 1;
this.isFixedGear = true;
}
gearing() {
if (this.isFixedGear === true) {
return (`This ${this.brand} is a fixed-gear.`);
}
}
}
It's easy to see that extends
directs subclass Fixie
to take on class Bicycle
's properties (much like the underscore library's extend
method extends an object(s) properties into another). Fixie
, however, has its own constructor that adds properties, and it overrides one of its inherited methods, gearing
.
What's less apparent here is that this code won't work as written. Attempting to create a new instance of Fixie
will throw a ReferenceError
Specifically, mine says Must call super constructor in derived class before accessing 'this' or returning from derived constructor
—if only all errors were this helpful! We'll need to user super
somehow to get things up and running—but how? And why?
According to javascript.info, "In JavaScript, there’s a distinction between a constructor function of an inheriting class (so-called “derived constructor”) and other functions." The problem is a derived constructor called with keyword new
does not create an empty object assigned to this
, because it "expects the parent constructor to do this job." So all we have to do is call the constructor in super (the parent class)—fair enough. Here's another go at it:
class Fixie extends Bicycle {
constructor(brand, color) {
super(brand, color);
this.chainRings = 1;
this.cogs = 1;
this.isFixedGear = true;
}
gearing() {
if (this.isFixedGear === true) {
return (`This ${this.brand} is a fixed-gear.`);
}
}
}
const moto = new Fixie("Motobecane", "blue");
console.log(moto.gearing()); /* This Motobecane is a
fixed-gear. */
The important thing to note is that super
must be called before any use of keyword this
, or there will be no this
to refer to, and an error will be thrown. Now let's look at one more use of super
:
class Fixie extends Bicycle {
constructor(brand, color) {
super(brand, color);
this.chainRings = 1;
this.cogs = 1;
this.isFixedGear = true;
}
gearing() {
if (this.isFixedGear === true) {
return (`This ${this.brand} is a fixed-gear.`);
}
}
describe() {
return `${super.describe()} This bike is a fixie.`
}
}
console.log(moto.describe()) /* This bicycle is a blue
Motobecane. This bike is a fixie. */
Now we've used a call of the super
's describe
method while actually overriding describe
within the subclass. The new method will return the value of describe
's message from the Bicycle
class along with more information describing the bike as a fixie.
Keyword super
doesn't have to be mysterious! Just remember that it refers to the parent class (thinking "superclass" may help), and that it must be called in the subclass's constructor function to start up a new empty object for keyword this
.
Super!
Top comments (3)
Thanks for this article! I was hoping you could clear something up, though, but no worries if not.
Why do you define chainrings and cogs within the gearing method in the Bicycle class, but in the Fixie class you define them in the constructor? Couldn't you have defined them all within the Bicycle's constructor and passed them as arguments when creating a new Fixie object? I'm kinda new to JavaScript classes, so forgive me if the answer is obvious.
Great read! I was having a bit of trouble wrapping my mind around Super and Extends and their use cases, but this brought me up to speed better than anything else I've looked at
Is there any point at all extending a class without using super?