JavaScript super
Keyword: Calling Superclass Constructors
In JavaScript, when working with classes and inheritance, the super
keyword plays a vital role. Specifically, when you create a subclass using the extends
keyword, the super
keyword is essential for calling the constructor of the parent class (also known as the superclass). This ensures that the parent class’s initialization logic is executed before the subclass’s own constructor logic. This article will delve into the purpose, syntax, and practical applications of the super
keyword within the context of class constructors.
Understanding the Need for super()
When a subclass extends a superclass, it inherits all the properties and methods of the superclass. However, if the superclass has a constructor, it’s imperative to call that constructor from the subclass’s constructor to properly initialize the inherited properties. The super()
keyword is the mechanism to achieve this.
Key Points:
- The
super()
method must be called before accessingthis
in the constructor of a subclass. ⚠️ - If you don’t call
super()
in the constructor of a subclass, JavaScript will throw an error. - You can pass arguments to
super()
which will then be passed to the superclass constructor.
Syntax of the super()
Keyword
The basic syntax of the super()
keyword within a subclass constructor is as follows:
class SuperClass {
constructor(param1, param2) {
// initialization logic
}
}
class SubClass extends SuperClass {
constructor(param1, param2, param3) {
super(param1, param2); // Calling Superclass constructor
// subclass-specific initialization
}
}
Here, super(param1, param2)
is calling the constructor of the SuperClass
passing the params to initialize the SuperClass
properties.
Using super()
with Parameters
Let’s look at examples with and without parameters. The super()
keyword allows passing parameters to the parent class constructor. If a superclass constructor accepts arguments, you must pass those arguments when calling super()
.
Example 1: Superclass constructor with no parameters
class Animal {
constructor() {
this.alive = true;
console.log("Animal is created");
}
speak() {
console.log("Generic Animal Sound");
}
}
class Dog extends Animal {
constructor(name) {
super(); // No parameters required to call parent constructor
this.name = name;
console.log(`Dog ${name} is created`);
}
speak() {
console.log("Woof!");
}
}
const dog1 = new Dog("Buddy");
dog1.speak();
console.log(dog1.alive)
Output:
Animal is created
Dog Buddy is created
Woof!
true
In this case, the Animal
constructor doesn’t require parameters. So we call super()
without any arguments in the Dog
constructor. It can be seen the Animal
constructor is called first, then the Dog
constructor.
Example 2: Superclass constructor with parameters
class Shape {
constructor(color, width) {
this.color = color;
this.width = width;
console.log(`Shape with color ${color} and width ${width} created`);
}
describe() {
console.log(`This is a shape with color: ${this.color} and width: ${this.width}`);
}
}
class Rectangle extends Shape {
constructor(color, width, height) {
super(color, width); // Passing parameters to the Shape constructor
this.height = height;
console.log(`Rectangle with color ${color}, width ${width} and height ${height} created`);
}
describe() {
console.log(`This is a rectangle with color: ${this.color}, width: ${this.width}, and height: ${this.height}`);
}
}
const rectangle1 = new Rectangle("blue", 10, 20);
rectangle1.describe()
Output:
Shape with color blue and width 10 created
Rectangle with color blue, width 10 and height 20 created
This is a rectangle with color: blue, width: 10, and height: 20
Here, the Shape
constructor requires parameters for color and width. The Rectangle
constructor passes these parameters when calling super(color, width)
, ensuring the Shape
class initializes these properties before the Rectangle
class sets up the height property.
Importance of Calling super()
First
The super()
call must be the first statement in the constructor of the subclass when you are inheriting from a superclass having a constructor. This is because the subclass needs the superclass to be properly set up before it can modify or extend that behavior. JavaScript enforces this rule strictly, and if you attempt to access this
before calling super()
, an error will be thrown.
Example Showing the error when calling this
before super()
class SuperClassExample {
constructor(name) {
this.name = name;
}
}
class SubClassExample extends SuperClassExample {
constructor(name, age) {
// this.age = age; // This will throw a reference error as you cannot use this before calling super()
super(name);
this.age = age;
}
}
try{
const subClassEx = new SubClassExample("John", 30);
}
catch (e){
console.error(e);
}
Output:
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
The error message explicitly indicates that you cannot access this
or return from the constructor before calling super()
. This highlights the critical order of operations within a subclass constructor.
Practical Use Cases
Let’s explore a more practical use case of the super
keyword within the context of rendering different shapes on a HTML Canvas.
Example: Canvas Shape Rendering with Inheritance
<canvas
id="canvasShapes"
width="300"
height="200"
style="border: 1px solid black;"
></canvas>
<script>
class ShapeCanvas {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
}
draw(ctx) {
// Placeholder
}
}
class CircleCanvas extends ShapeCanvas {
constructor(x, y, color, radius) {
super(x, y, color);
this.radius = radius;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fillStyle = this.color;
ctx.fill();
}
}
class RectangleCanvas extends ShapeCanvas {
constructor(x, y, color, width, height) {
super(x, y, color);
this.width = width;
this.height = height;
}
draw(ctx) {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
const canvas_shapes = document.getElementById("canvasShapes");
const ctx_shapes = canvas_shapes.getContext("2d");
const circle = new CircleCanvas(50, 50, "red", 30);
circle.draw(ctx_shapes);
const rectangle = new RectangleCanvas(150, 50, "blue", 80, 60);
rectangle.draw(ctx_shapes);
</script>
In this example, ShapeCanvas
is the parent class with common properties such as x
, y
position and color
. The CircleCanvas
and RectangleCanvas
classes inherit from ShapeCanvas
. The super()
keyword is used to call the ShapeCanvas
constructor to set the base properties.
super
in Method Overriding
Apart from calling superclass constructors, the super
keyword can also be used to call superclass methods from overridden methods in subclasses, but that will be discussed in detail in future articles.
Conclusion
The super
keyword in JavaScript classes is crucial for managing inheritance and ensuring the proper initialization of objects. By calling the parent class constructor using super()
, subclasses inherit and initialize the parent’s properties and methods correctly. Always remember to call super()
before accessing this
within a subclass constructor to avoid runtime errors. This understanding is essential for building robust and well-structured object-oriented JavaScript applications.