3

I'm trying to use the revealing prototype patter to extend a "class". As an example I have an Animal and a Fish.

Here's what I'd like to be able to to:

  • Fish to Inherit the prototype from Animal
  • Override members of Animal if needed
  • Add new members to the Fish prototype
  • Do all this while still using the revealing prototype pattern for both "classes"

I can create the Animal "class":

var Animal = function(data) {
  this.name = ""
  this.color = "";
  this.weight = 0;
};


Animal.prototype = function() {
  var eat = function() {
    document.write(this.name + " is eating.<br>");
  }

  return {
    constructor: Animal,
    eat: eat
  };
}();

And I can create a Fish "class" that inherits from Animal:

var Fish = function(data) {
  this.isSwimming = false;
};


Fish.prototype = new Animal();

The prototype for the Fish is where I'm running into trouble. Is it possible to use the revealing prototype pattern for Fish and still inherit the prototype from Animal and override Animal if needed? (I'm not completely opposed to using a third party library to do this, but I'd prefer not to.) For example, how could I override eat() and add a new function to Fish called swim?

Edit:

Here's what I've come up with. This seems to do what I need. Am I missing anything?

Fish.prototype = new function(proto) {
  var base = proto.constructor;

  var eat = function(data) {
    new base().eat (data);//This is just to show you can call the base. If needed.
    document.write("fish eating.<br>");
  };

  var swim = function(){
    document.write("fish is swimming.<br>");
  };

  var thisProto = {
    constructor: Fish,
    eat: eat,
    swim: swim
  };

  for (var propt in thisProto) {
    proto[propt] = thisProto[propt];
  }

  return proto;
}(new Animal());

Edit:

In the answer I accepted, one of the main points was to not use the new keyword. So I researched the difference between the new keyword and Object.create(). If I understand things correctly, they both do basically the same thing, but Object.create() will not call the objects constructor while the new keyword will. If you need to inherit something that is defined in the constructor, you'll need to use the new keyword or move that member to the prototype.

Here's a plunk that I used to experiment with this some more: http://plnkr.co/edit/322WB4jyCJberABbb0P0

Jeff
  • 2,728
  • 3
  • 24
  • 41
  • possible duplicate of [How to implement inheritance in JS Revealing prototype pattern?](http://stackoverflow.com/questions/9248655/how-to-implement-inheritance-in-js-revealing-prototype-pattern) – Bergi Mar 06 '14 at 15:56
  • @Bergi, I'm testing your answer now. I did see that other answer yesterday, but just couldn't get my head around it. Now that I look at it today it make more sense and it probably is a duplicate, but I think your answer adds more information. – Jeff Mar 06 '14 at 16:12

1 Answers1

2

Am I missing anything?

Yes.

new function(proto) {

Do not use new.

new base().eat (data);//This is just to show you can call the base. If needed.

Do not use new. You'd create a new instance here, however what you want is get the eat method from the base.prototype and call that on your Fish instance.

proto = new Animal()

Do not use new!


Fish.prototype = (function(super) {
  var proto = Object.create(super);

  function eat(data) {
    super.eat.call(this, data);
    document.write("fish eating.<br>");
  }
  function swim(){
    document.write("fish is swimming.<br>");
  }

  proto.constructor = Fish;
  proto.eat = eat;
  proto.swim = swim;

  return proto;
})(Animal.prototype);
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Why didn't you set the constructor in the following manner: var Fish = function(data) { Animal.call(this, data); }; For the example list in this article, http://stackoverflow.com/questions/9248655/how-to-implement-inheritance-in-js-revealing-prototype-pattern, that is what they did there? I notice that is not being done here. – user1790300 Oct 18 '16 at 15:21
  • @user1790300 Ah, I forgot about that as I focused on the pattern for `Fish.prototype` here. Yes, the constructor should call the super constructor for property initialisation just like in my answer that you linked – Bergi Oct 18 '16 at 15:37
  • I am new to this level of javascript development, apologies, but I am confused as to how that initializes the base constructor if you are using Object.create(super) to create a new instance of the animal object, it seems like there is a disconnect? Does this mean that proto is pointing to the same instance of Animal that Animal.call passes arguments to? If this is a left field question, I apologize. – user1790300 Oct 18 '16 at 15:49
  • Also, why did you call super.eat.call(this, data); instead of proto.eat(data);? – user1790300 Oct 18 '16 at 16:06
  • @user1790300 `proto = Object.create(super)` does not create an animal instance (or initialise it like `new Animal()` would), it just creates an object that inherits from `Animal.prototype`. This object becomes the `Fish.prototype`, so all instances that are created using `new Fish` will inherit from it. `proto` is *not* the same as `this` inside the constructor or the methods. – Bergi Oct 18 '16 at 16:25
  • What would I have to do to use the instance I initialized in the constructor, var Fish = function(data) { Animal.call(this, data); };? – user1790300 Oct 18 '16 at 17:16
  • @user1790300 What do you mean by "use"? Just `var fish = new Fish({}); fish.eat(); fish.swim();`? – Bergi Oct 18 '16 at 17:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126047/discussion-between-user1790300-and-bergi). – user1790300 Oct 18 '16 at 20:12