Learn by reading through in order

Inheritance — extends and super

Build a new class on top of an existing one with extends. Covers super() in a child constructor, overriding, and super.methodName().

Say an online bookstore needs a class for e-books alongside its Book class for print books. The only differences are that e-books can be downloaded and don't have a shipping fee, yet with what you know so far, you'd end up rewriting the parts that handle the title and price as well.

This article covers extends, which builds on an existing class, and super, which calls code in the class you built on.

Reusing Code Without Copying It — extends

E-books also need a constructor that takes a title and a price, and a describe method that returns "title: price yen". If you copy the body of Book into a new e-book class, the same lines exist in two places. If you later change the display format and forget to update one copy, different screens end up showing different formats.

Inheritance (a way to let another class use an existing class's constructor and methods) is written as class EBook extends Book. Book is called the parent class, and EBook the child class.

The extends Error you wrote in the throw and custom errors article is inheritance too.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
  describe() { return `${this.title}: ${this.price} yen`; }
}

// Builds on Book and adds a method only e-books have
class EBook extends Book {
  download() { return `Downloading ${this.title}`; }
}

const ebook = new EBook("Stats 101", 2200);   // The arguments go to Book's constructor
console.log(ebook.describe());               // Stats 101: 2200 yen
console.log(ebook.download());               // Downloading Stats 101

const book = new Book("Stats 101", 2640);
console.log(typeof book.download);           // undefined (a parent class doesn't have its child's methods)
The Inheritance Tree from Book to EBook
class Bookconstructor,describebook can onlycall describeclass EBookextends BookEBook onlydefines downloadInstance madeby new EBook(...)Can call bothdescribe anddownload
EBook only defines download, but you can still call describe on it. The reverse doesn't work: book can't call download.

Inside ebook.describe(), this is ebook, so the this.title written in Book reads the title you passed to new EBook. And it was Book's constructor, receiving those arguments, that put the title on ebook in the first place.

You'll display a log entry for each password an admin resets. User and targets are already declared.

① Define AdminUser, which inherits from User.

② Add resetPassword, which returns a log entry combining the admin's own description and the other user's name.

③ Create an admin and display a log entry for everyone in targets.

④ Display whether the admin is also an instance of User.

(If it runs correctly, an explanation will appear.)

JavaScript / TypeScript Editor

Run code to see output

Adding Values in a Child Class — super() and the constructor

Now suppose e-books also need to hold their file size, fileSize, in addition to the title and price. To accept the file size, EBook needs its own constructor. But once you write one, Book's constructor is no longer called automatically, and if you leave it at that, new throws a ReferenceError.

super() (a way to call the parent class's constructor from inside a child class's constructor) takes the arguments to pass to the parent, as in super(title, price);.

In a child class, this is set up by the parent's constructor during super(), so call it before any line that uses this.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
}

class EBook extends Book {
  constructor(title, price, fileSize) {
    // Writing this.fileSize = fileSize; above this line makes new throw a ReferenceError
    super(title, price);          // Book's constructor sets title and price
    this.fileSize = fileSize;     // Then add the value only EBook has
  }
}

const ebook = new EBook("Stats 101", 2200, 12);
console.log(ebook.title);                      // Stats 101
console.log(ebook.fileSize);                   // 12
console.log(Object.keys(ebook).join(", "));    // title, price, fileSize
Is super() Called Before this?
this.fileSizewritten firstsuper() notcalled yetThrows at the linethat uses thisReferenceErrorat newsuper(title,price) writtenfirstBook setstitle and pricethis.fileSizeis set to 12ebook holdsall 3 values
In the top row, using this before super() throws an error, and no instance is created. You can use this only after super() has finished.

The keys come out in the order title, price, fileSize because Book set its values first, inside super(). The top row fails with ReferenceError: Must call super constructor in derived class before accessing 'this' …, where "derived class" means the child class.

A Child Class Can't Read the Parent's # Fields

If Book has a private field #price, super() still sets its value, but writing this.#price in the body of EBook is a SyntaxError. A # name can only be used inside the class that declares it, so a child class has to read it through a getter defined in the parent.

You'll list each admin's permissions on an admin screen. User and adminInput are already declared.

① Define AdminUser, which inherits from User and takes a name, an email, and an array of permissions.

② Set the name and email in User's constructor.

③ Create an admin from adminInput and display the name along with a breakdown of the permissions.

④ Display the keys in order, and check where the status defined in User appears.

JavaScript / TypeScript Editor

Run code to see output

Changing the Shipping Fee in a Child Class — Overriding

If you add a shippingFee method to Book, e-books get the same shipping fee as print books. You could make it 0 yen for e-books only by checking the book type with if inside Book, but then the parent class needs another branch every time you add a child class.

Overriding (writing a method in a child class with the same name as one in the parent, so the child's version runs for the child's instances) just means writing shippingFee again in the body of EBook. When you call a method, JavaScript looks for the name starting in the class that created the instance, and moves on to the parent class if it isn't there.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
  describe() { return `${this.title}: ${this.price} yen`; }
  shippingFee() { return this.price >= 3000 ? 0 : 500; }   // Free shipping at 3000 yen or more
}

class EBook extends Book {
  shippingFee() { return 0; }   // Overridden under the same name (nothing to ship)
}

const book = new Book("Stats 101", 2640);
const ebook = new EBook("Stats 101", 2200);
console.log(book.shippingFee());    // 500
console.log(ebook.shippingFee());   // 0 (EBook's shippingFee runs)
console.log(ebook.describe());      // Stats 101: 2200 yen (Book's describe runs)
Where JavaScript Looks for a Called Method
EBook overridesonly shippingFeebook.shippingFee()ebook.shippingFee()ebook.describe()Starts in Book,found in BookStarts in EBook,found in EBookNot in EBook,found in Book2640 is under3000, so 5000, withoutchecking BookStats 101:2200 yen
The search starts in the class that created the instance. If it's found in EBook, Book's method with the same name doesn't run.

EBook's shippingFee doesn't use Book's calculation, so even if you change Book's shipping rules, e-books stay at 0 yen. The next section covers how to call the parent's code and then add only what's different.

On an internal message board, you'll decide whether to show an edit button for each post. User and posts are already declared.

① Define AdminUser, which inherits from User, and override the check so an admin can edit any post.

② Create a regular user "Bob" and an admin "Alice".

③ For each post, display whether each of them can edit it, in the form "Post N: Bob X / Alice Y".

JavaScript / TypeScript Editor

Run code to see output

Adding to the Parent's Code — super.methodName()

Next, suppose you want e-book descriptions to end with "(e-book, 12 MB)". If you override describe in EBook and copy over the code that builds "title: price yen", then the next time you change Book's display format, the e-book descriptions will be left in the old format.

With super.methodName() (a way to call a method defined in the parent class from inside a child class's method), super.describe() returns the value of Book's describe. The child class only has to add the e-book details to that string.

class Book {
  constructor(title, price) {
    this.title = title;
    this.price = price;
  }
  describe() { return `${this.title}: ${this.price} yen`; }
}

class EBook extends Book {
  constructor(title, price, fileSize) {
    super(title, price);
    this.fileSize = fileSize;
  }

  // Adds the e-book details to the return value of Book's describe
  describe() { return `${super.describe()} (e-book, ${this.fileSize} MB)`; }
}

const ebook = new EBook("Stats 101", 2200, 12);
console.log(ebook.describe());   // Stats 101: 2200 yen (e-book, 12 MB)
What Runs Inside ebook.describe(), in Order
ebook.describe()starts runningthis is ebook(fileSize is 12)super.describe()runs Book'sdescribethis is stillebook: Stats 101:2200 yenAdds (e-book,12 MB) to thereturn valueReturns Stats 101:2200 yen(e-book, 12 MB)
Book's describe runs partway through EBook's describe and then returns. The code that builds the title and price exists only in Book.

super.describe() is an expression that evaluates to Book's return value, so if you'd rather put the e-book details first, just move it within the template literal. The table below summarizes the inheritance syntax used in this article and what runs for each.

SyntaxWhere It GoesWhat Runs
class EBook extends BookClass declarationInherits Book's constructor and methods
super(title, price)Child constructor, before thisBook's constructor
Method with the parent's nameChild class bodyEBook's version, for EBook instances
super.describe()Inside a child methodBook's describe

Without super, the Method Calls Itself Forever

If you write this.describe() instead of super.describe() in the child class's describe, the method keeps calling itself until it throws RangeError: Maximum call stack size exceeded. To call the parent's code from a method you've overridden, use super..

In an internal tool, you'll apply a stricter password rule to admins only. User, AdminUser, admin, member, and passwords are already declared.

① Add checkPassword to AdminUser. It should run User's check first and, if that passes, also check for at least 12 characters.

② Check the passwords in order as the admin, and display the results.

③ Check the second password as the regular user, and display the result.

JavaScript / TypeScript Editor

Run code to see output
QUIZ

Knowledge Check

Answer each question one by one.

Q1What happens when you call new on an EBook that assigns to this.fileSize before super()?

Q2If both Book and EBook have a shippingFee method, which one runs when you call ebook.shippingFee()?

Q3Inside EBook's describe, how do you get the return value of Book's describe?