Inheritance with extends and super

A manager is an employee with a team. You don't want to write all of Employee again just to add one property. With extends, a new class can build on an existing class:

class Employee {
  constructor(name, salary) {
    this.name = name;
    this.salary = salary;
  }

  describe() {
    return `${this.name} earns ${this.salary}`;
  }
}

class Manager extends Employee {
  constructor(name, salary, teamSize) {
    super(name, salary);
    this.teamSize = teamSize;
  }

  describe() {
    return `${this.name} manages ${this.teamSize} people`;
  }
}

const carol = new Manager("Carol", 4200, 5);
console.log(carol);
console.log(carol.describe());

Output:

Manager { name: 'Carol', salary: 4200, teamSize: 5 }
Carol manages 5 people

Manager extends Employee means a manager gets everything an employee has. We say Manager inherits from Employee. Employee is the parent class, and Manager is the child class. The child only writes what is different.

The child's constructor first calls super(name, salary). This runs the parent's constructor, which sets name and salary. Then the child adds its own property, teamSize.

Manager also has its own describe method. It replaces the parent's version for managers. This is called overriding.

The real benefit shows when different kinds of objects go through the same code. Here the class Intern adds nothing at all. It has no constructor, so the values go straight to the constructor of Employee. It also has no describe, so it uses the one from Employee:

<!-- continues -->
class Intern extends Employee {}

const staff = [
  new Employee("Alice", 3000),
  new Manager("Carol", 4200, 5),
  new Intern("Dave", 1500),
];
for (const person of staff) {
  console.log(person.describe());
}

Output:

Alice earns 3000
Carol manages 5 people
Dave earns 1500

The loop calls describe on every person, and each one answers in the way its own class defines. This idea is called polymorphism. When JavaScript looks for a method, it first checks the object's own class, then the parent class. That is why Dave the intern gets the parent's describe. If you add a new child class later, this loop works for it without any change.

In a child's constructor, you must call super before you use this. If you forget, you get an error:

class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name) {
    this.sound = "woof";
    super(name);
  }
}

const rex = new Dog("Rex");

Output:

/box/index.js:9
    this.sound = "woof";
    ^

ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    at new Dog (/box/index.js:9:5)
    at Object.<anonymous> (/box/index.js:14:13)

Use extends only when the child really is a kind of the parent. A manager is an employee, so that fits. But a team is not a kind of array. A team has a list of people, so give it a property that holds an array instead. Keep class families small, with one or two levels.

In the exercise, complete a Manager class: call super in its constructor, and override describe.