ES5 Class InheritanceLoading saved progress…

ES5 Class Inheritance

Classical inheritance in JavaScript is set up by linking one constructor's prototype to another's, so instances of the child inherit the parent's methods and satisfy instanceof for both. Before ES6 added class and extends, you wired this by hand — and class Child extends Parent still desugars to exactly these steps. Implement es5Extends(Child, Parent) so that, after you call it, Child inherits from Parent the classic prototypal way: no class, no extends. See MDN on inheritance and the prototype chain.

Signature

es5Extends(Child: Function, Parent: Function): Function
//   mutates Child so its instances inherit from Parent; returns Child

Examples

function Animal(name) {
  this.name = name;
}
Animal.prototype.describe = function () {
  return this.name + ' is an animal';
};
Animal.prototype.legs = function () {
  return 4;
};

function Dog(name, breed) {
  Animal.call(this, name); // run the parent constructor on `this` (the ES5 super call)
  this.breed = breed;
}

es5Extends(Dog, Animal); // wire inheritance BEFORE adding Dog's own methods

Dog.prototype.describe = function () {
  // extend the parent method by reaching it through the prototype
  return Animal.prototype.describe.call(this) + ' (a dog)';
};

const d = new Dog('Rex', 'pug');
d.name; // 'Rex'    — set by Animal.call
d.legs(); // 4      — inherited from Animal.prototype
d.describe(); // 'Rex is an animal (a dog)'
d instanceof Dog; // true
d instanceof Animal; // true
d.constructor === Dog; // true — the constructor pointer is restored
// Inheritance is one-directional, and the link must NOT run the parent:
new Animal('Spot') instanceof Dog; // false

function Base(required) {
  if (required === undefined) throw new Error('needs an argument');
  this.required = required;
}
function Derived() {
  Base.call(this, 'ok');
}
es5Extends(Derived, Base); // must NOT throw — the link is Object.create, not new Base()

Notes

  • Link the prototype chain — set Child.prototype = Object.create(Parent.prototype) so a lookup that misses on the instance walks up to Parent.prototype. This is what makes inherited methods and instanceof Parent work.
  • Do not build the link with new Parent() — that runs the parent constructor with no arguments (it may throw) and copies stray fields onto the shared prototype. Use Object.create instead.
  • Restore constructor — replacing Child.prototype wipes its constructor, so set Child.prototype.constructor = Child or instance.constructor wrongly points at Parent.
  • The super calls live in the child, not in es5Extends — the child constructor runs the parent's with Parent.call(this, ...args); a child method reuses the parent's with Parent.prototype.method.call(this).
  • Inherit statics too — make Child itself delegate to Parent with Object.setPrototypeOf, so the parent's static members are reachable on Child.
  • Don't use class / extends — reproduce the wiring by hand; that is the exercise.
Loading editor…