1

Is it possible to get Dog and Cat to inherit from Animal (without using the class or extends keywords), without editing the code that has already been written, and while keeping all new code within the current constructor functions?

function Animal() {
  this.sleep = function() {
    var hoursSleepPerNight = this.hoursSleepPerNight;
    console.log( "z".repeat(hoursSleepPerNight) );
  }
}

function Dog() {
  this.hoursSleepPerNight = 8;
}

function Cat() {
  this.hoursSleepPerNight = 7;
}

var dog = new Dog();
dog.sleep();
// "zzzzzzzz"
lucasjackson
  • 1,515
  • 1
  • 11
  • 21
Trajanson
  • 441
  • 3
  • 11
  • `Dog.prototype = Object.create(Animal.prototype)`, but note that `sleep` is an own property, it won't be inherited. You could try `Dog.prototype = new Animal()` but be aware of side-effects. – elclanrs Jul 02 '16 at 18:00
  • Why would you want to do that? – Bergi Jul 02 '16 at 18:11
  • @Bergi, wishful thinking that JavaScript can be forced to behave like Python/Ruby I suppose. – Trajanson Jul 02 '16 at 18:42
  • It also seems unnatural to me that inheritance would be added *after* defining a "class"'s own methods and properties. I assumed there had to be a better way. – Trajanson Jul 02 '16 at 18:47
  • @Trajanson: Well you seem to have a solution already: `class`+`extends`, not different than in Python. Also you usually would define (prototype) methods *after* doing the inheritance? – Bergi Jul 03 '16 at 09:07

2 Answers2

2

Javascript uses prototypal inheritance, so you can inherit from Animal as follows:

function Animal() {
  this.sleep = function() {
    console.log("z".repeat(this.hoursSleepPerNight));
  }
}

function Dog() {
  this.hoursSleepPerNight = 8;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

function Cat() {
  this.hoursSleepPerNight = 7;
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;

var dog = new Dog();
dog.sleep();

Here is a fiddle: https://jsfiddle.net/k0op9sb6/

If for some reason you must set the prototype within the constructor functions it looks like you may be able to use Object.setPrototypeOf or __proto__ (proto) -- HOWEVER this is universally NOT RECOMMENDED:

function Dog() {
  this.hoursSleepPerNight = 8;
  Object.setPrototypeOf(this, new Animal()); // this.__proto__ = new Animal();
}
lucasjackson
  • 1,515
  • 1
  • 11
  • 21
  • Any thoughts on why `this.prototype = new Animal();` cannot be moved inside the Dog constructor? – Trajanson Jul 02 '16 at 18:45
  • 1
    Setting `this.prototype` adds an own property `prototype` to your instance. This is not the same as setting Function.prototype. It looks like you can get the behavior you are looking for by setting `this.__proto__` (updated above). – lucasjackson Jul 02 '16 at 19:33
  • 1
    Please use [`Object.create(Animal.prototype)` instead of `new Animal`](http://stackoverflow.com/a/17393153/1048572?Benefits-of-using-Object.create-for-inheritance) to do it properly, and use `Object.setPrototypeOf` instead of the deprecated `__proto__`. – Bergi Jul 03 '16 at 09:09
  • @Bergi where does that line go? That was one of my original confusions. `Object.setPrototypeOf(Dog) = Object.create(Animal.prototype);` after the constructor does not work. `Dog.prototype = Object.create(Animal.prototype);` does not work #=> TypeError: dog.sleep is not a function – Trajanson Jul 03 '16 at 13:12
  • 1
    @Trajanson you should be able to replace `this.__proto__ = new Animal();` with `Object.setPrototypeOf(this, new Animal());` (updated above). If you want your children objects to inherit the sleep method, however, setting the prototype with `Object.create(Animal.prototype)` won't work since it's an own property. The typical javascript way of handling this would be to move your `sleep` function to the `Animal` prototype, and then have your children inherit as follows: `Dog.prototype = Object.create(Animal.prototype);` (not within your constructor function). – lucasjackson Jul 03 '16 at 13:20
  • @lucasjackson: You should add a `Animal.call(this)` "super" call in the constructor anyway, then properties and privileged methods will be created as well. – Bergi Jul 03 '16 at 15:29
2

No, it is not possible (and not sensible) to keep all inheritance-related code inside the constructor if you are looking for prototypical inheritance.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375