Can I apply a prototype to a js constructor (as opposed to the instances it creates)?

29 views Asked by At

I am attempting to use constructor created objects with prototypes in javascript.

I would like to apply a prototype to the constructor so that any objects it creates inherit the prototype automatically. Is this possible?

I only seem to be able to apply the prototype to individual instances created by the constructor, and not to the constructor itself.


I am aiming for something like this:

var animal = {
    speak: function(){ console.log(this.name + ' says ' + this.sound); }
}    

var dog = function(name){
    this.name = name;
    this.sound = 'bark';
}
dog.__proto__ = animal;

var pig = function(name){
    this.name = name;
    this.sound = 'oink';
}
pig.__proto__ = animal;

var percy = new pig("percy");
percy.speak();

var fido = new dog("fido");
fido.speak();

The above gives me the error: percy.speak is not a function.

It seems that the __proto__ declaration is not being applied to pig or dog.

In contrast, it DOES let me apply the __proto__ declaration to percy or fido directly:

var animal = {
    speak: function(){ console.log(this.name + ' says ' + this.sound); }
}


var dog = function(name){
    this.name = name;
    this.sound = 'bark';
}

var pig = function(name){
    this.name = name;
    this.sound = 'oink';
}

var percy = new pig("percy");
percy.__proto__ = animal;
percy.speak();

This works, and gives me percy says oink, as expected.

1

There are 1 answers

1
Oriol On BEST ANSWER

First, never use __proto__. Use Object.getPrototypeOf or Object.setPrototypeOf.

__proto__ is a non-standard accessor which should have never existed and may not work if your object does not inherit from Object.protoype or __proto__ has been shadowed. Moreover, changing the [[Prototype]] of an object has a big impact in performance, see the warning in MDN.

Second, you are not supposed to mess with [[Prototype]]s when adding methods.

Add them to the prototype instead.

var animalProto = {
  speak: function(){ console.log(this.name + ' says ' + this.sound); }
};
var dog = function(name){
  this.name = name;
  this.sound = 'bark';
};
dog.prototype = animalProto;

var pig = function(name){
  this.name = name;
  this.sound = 'oink';
};
pig.prototype = animalProto;

var percy = new pig("percy");
percy.speak();

var fido = new dog("fido");
fido.speak();

But it would be cleaner using classes:

class Animal {
  constructor(name, sound) {
    this.name = name;
    this.sound = sound;
  }
  speak() {
    console.log(this.name + ' says ' + this.sound);
  }
}
class Dog extends Animal {
  constructor(name) {
    super(name, 'bark');
  }
}
class Pig extends Animal {
  constructor(name) {
    super(name, 'oink');
  }
}

var percy = new Pig("percy");
percy.speak();

var fido = new Dog("fido");
fido.speak();