Bisexual Pride

In JavaScript, you can use the extends keyword to implement inheritance, i.e. create a derived class from a base class. But did you know that you can use it to extend any constructor? The base “class” doesn’t have to be declared using the class syntax.

function Hero(name, level) {
this.name = name;
this.level = level;
}

Hero.prototype.greet = function () {
return `${this.name} says hello.`;
};

class Warrior extends Hero {
constructor(name, level, weapon) {
super(name, level);
this.weapon = weapon;
}

attack() {
return `${this.name} attacks with the ${this.weapon}.`;
}
}

To be extensible, the base “class” must be a valid constructor. This means it must have a .prototype property and be callable with the new operator. Generally speaking, this includes “regular” function declarations and function expressions. It may also be null, but there is an important “gotcha” when extending null.

Functions without a .prototype property include (but are not limited to): Proxy, arrow function expressions, async function declarations, async function expressions, bound functions, and method definitions. Functions that throw an error when called with new include (but are not limited to): Symbol, BigInt, generator function declarations, generator function expressions, async generator function declarations, and async generator function expressions.

Why mix the prototypal syntax with the class syntax? You probably wouldn’t do this in new code, but it could be useful if you were extending a “class” in legacy code and didn’t have time to refactor it.