1

Say I have 5 Objects

Callback
Perishable
Object1
Object2
Object3

Object1 needs to extend the Callback but not the Perishable object, whereas Object 2 should extend both and Object 3 should extend Perishable but not callback.

I know this works...

Object1.prototype = new Callback();
Object3.prototype = new Perishable();

but how would I do something like (I know this isnt working)

Object2.prototype = new Callback() && new Perishable();
Jackie
  • 21,969
  • 32
  • 147
  • 289
  • JavaScript doesn't have multiple differential inheritance. However you can inherit from both `Callback.prototype` and `Perishable.prototype` via concatenation. Read the following article: http://aaditmshah.github.io/why-prototypal-inheritance-matters/#toc_8 – Aadit M Shah Nov 06 '14 at 16:23
  • 2
    Not directly related to your problem, but you should [avoid using `new Constructor()` for your prototypes](http://programmers.stackexchange.com/questions/198267/why-is-the-use-of-constructors-discouraged-when-creating-prototypes), use `Object.create(Constructor.prototype)` (or any other object you want to be the prototype of the created object). – apsillers Nov 06 '14 at 16:26
  • 1
    Your code is wrong; see http://blog.slaks.net/2013-09-03/traditional-inheritance-in-javascript/ – SLaks Nov 06 '14 at 16:26
  • I am not doing anything in my constructor, and I got my point across so I am not that worried. However, both of those were good reads and had me think a lot about our current patterns. – Jackie Nov 06 '14 at 18:15
  • So it is weird after looking at that link SLaks it looks like I only need 'Callback.call(this);' and not the other stuff http://plnkr.co/edit/8xQxscg1UXj3QuiEoQWj. Not sure what I am missing about the rest of what he is doing but maybe that is another question. – Jackie Nov 06 '14 at 19:10

3 Answers3

2

You can use extend function from Underscore.js library.

The code would look like this:

_.extend(Object1.prototype, Callback.prototype);
_.extend(Object1.prototype, Perishable.prototype);

Here's JS fiddle: http://jsfiddle.net/yb7kkh4e/2/

2

If you don't want any external dependencies, you can use this implementation of extend:

function __extends(d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    var a = function(){}; a.prototype = new b();
    for (var p in a.prototype) d.prototype[p] = a.prototype[p];   
};

Example:

var animal = function(){

};

animal.prototype.run = function(){
     console.log("running");   
};

var feline = function(){

};

feline.prototype.hunt = function(){
     console.log("hunting");   
};

var cat = function(){

};

__extends(cat, animal);
__extends(cat, feline);

var scaryCat = new cat();

scaryCat.run();

scaryCat.hunt();

Fiddle: http://jsfiddle.net/apqwf93a/9/

Cristi Pufu
  • 9,002
  • 3
  • 37
  • 43
1

Usually when you want to extend multiple objects you have to look if your design is correct. Is the object the other object?

For example a Cat is an Animal and a Cat can move. To extend the Cat from Movable would be wrong because the Cat is not a Movable it can move so it should implement Movable or leave default implementation of Movable.

The example of Cat Feline and Animal is fine but could be solved without multiple inheritance. A Cat is a Feline and a Feline is an Animal so no reason for Cat to both inherit from Feline and Animal you could have Cat inherit from Feline and Feline from Animal.

The chosen answer deals with the prototype part of mix ins (implements) but doesn't cover how to initialize instance specific members. Here is the mix in part of the following answer that does:

Multiple inheritance with mix ins

Some things are better not to be inherited, if a Cat can move and than a Cat should not inherit from Movable. A Cat is not a Movable but rather a Cat can move. In a class based language Cat would have to implement Movable. In JavaScript we can define Movable and define implementation here, Cat can either override, extend it or us it's default implementation.

For Movable we have instance specific members (like location). And we have members that are not instance specific (like the function move()). Instance specific members will be set by calling mxIns (added by mixin helper function) when creating an instance. Prototype members will be copied one by one on Cat.prototype from Movable.prototype using the mixin helper function.

var Mixin = function Mixin(args){
  var i, len;
  if(this.mixIns){
    i=-1;len=this.mixIns.length;
    while(++i<len){
        this.mixIns[i].call(this,args);
      }
  }  
};
Mixin.mix = function(constructor, mix){
  var thing
  ,cProto=constructor.prototype
  ,mProto=mix.prototype;
  //no extending, if multiple prototype uhs
  // have members with the same name then use
  // the last
  for(thing in mProto){
    if(Object.hasOwnProperty.call(mProto, thing)){
      cProto[thing]=mProto[thing];
    }
  }
  //instance intialisers
  cProto.mixIns = cProto.mixIns || [];
  cProto.mixIns.push(mix);
};
var Movable = function(args){
  args=args || {};
  //demo how to set defaults with truthy
  // not checking validaty
  this.location=args.location;
  this.isStuck = (args.isStuck===true);//defaults to false
  this.canMove = (args.canMove!==false);//defaults to true
  //speed defaults to 4
  this.speed = (args.speed===0)?0:(args.speed || 4);
};
Movable.prototype.move=function(){
  console.log('I am moving, default implementation.');
};
var Animal = function(args){
  args = args || {};
  this.name = args.name || "thing";
};
var Cat = function(args){
  Animal.call(args);
  //if an object can have others mixed in
  //  then this is needed to initialise 
  //  instance members
  Mixin.call(this,args);
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Mixin.mix(Cat,Movable);
var poochie = new Cat({
  name:"poochie",
  location: {x:0,y:22}
});
poochie.move();
Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
  • To be honest I did rethink my model and I did change the inheiratence chain. This is still a really good idea because the times I really need it are when I am re-factoring and see a bunch of shared code. I think mixins do tend to fit better in those cases. For now though the question is what it is. – Jackie Nov 07 '14 at 14:24