ILikeThePoopSmith
ILikeThePoopSmith

Reputation: 121

Syntax question about ES6 classes (constructor/super)

As this example is copy/pasted from inline tags in my html file, the formatting may be off.

Anyhow, I'm new to JS and have a syntax question. This example is from an MDN basics of JS article. Here is a simple shape class:

class Shape {
  constructor(name, sides, sideLength) {
    this.name = name;
    this.sides = sides;
    this.sideLength = sideLength;
  }
  calcPerimeter() {
    console.log(this.sides * this.sideLength);
  }
}

Then, I want to extend it with a Square class

class Square extends Shape {
  constructor(name, sides, sideLength) {
    super(name, sides, sideLength);
  }
  calcArea() {
    console.log(this.sideLength * this.sideLength);
  } 
}

Now, this is obviously a bit silly. It's a Square class, so the name should always be "square", and it should always have 4 sides. We can remove the name and sides parameters.

class Square extends Shape {
  constructor(sideLength) {
    super(sideLength);
    this.name = "square;
    this.sides = 4;
  }
  calcArea() {
    console.log(this.sideLength * this.sideLength);
  } 
}

The problem is this doesn't work, and I'm not sure why. I would think I could now do let square = new Square(5); but sideLength is undefined. If I explicitly set this.sideLength to sideLength in Square class, it fixes the problem, but then I'm not inheriting anything from Shape class. What's wrong with my syntax here? How do I do what I'm trying to do (inherit sideLengths from Shape)?

Upvotes: 1

Views: 63

Answers (2)

Fullstack Guy
Fullstack Guy

Reputation: 16908

To follow the inheritance hierarchy, you need to call the super constructor with the values from the child constructor. You do not need to assign new properties to this instead you can pass the properties for the Square using the super(...) call:

class Shape {
  constructor(name, sides, sideLength) {
    this.name = name;
    this.sides = sides;
    this.sideLength = sideLength;
  }
  calcPerimeter() {
    console.log(this.sides * this.sideLength);
  }
}

class Square extends Shape {
  constructor(sideLength) {
    super("square", 4, sideLength);
  }
  calcArea() {
    console.log(this.sideLength * this.sideLength);
  } 
}

const square = new Square(5);
square.calcArea();

When you do not pass the properties name and sides to the parent constructor and only pass sidelength, the name gets initialized with the value of sidelength due to the position of the parameter in the parent constructor:

constructor(sideLength) {
     super(sideLength);
     this.name = "square";
     this.sides = 4;
}

Makes the call to the parent constructor like so:

Shape(sidelength, undefined, undefined)

So as the last parameter which is sidelength becomes undefined, when you try to call the calcArea it does not work.

Upvotes: 2

CertainPerformance
CertainPerformance

Reputation: 370689

When you do

super(sideLength);

This calls the parent constructor with one argument, the sideLength. So, this runs:

  constructor(name, sides, sideLength) {
    this.name = name;
    this.sides = sides;
    this.sideLength = sideLength;
  }

which turns into, since only the first argument, name, has a value in it:

this.name = sideLengthPassedFromSquare;
this.sides = undefined;
this.sideLength = undefined;

IF you want to be able to omit properties passed like this, have the super constructor either list the required properties first (like sideLength):

  constructor(sideLength, name, sides) {

Or pass a single object instead:

constructor({ name, sides, sideLength }) {

and do

super({ sideLength })

Upvotes: 1

Related Questions