1

I'm not very well aquainted with javascript inheritance, and I'm trying to make one object inherit from another, and define its own methods:

function Foo() {}
Foo.prototype = {
    getColor: function () {return this.color;},
};
function FooB() {}
FooB.prototype = new Foo();
FooB.prototype = {
    /* other methods here */
};

var x = new FooB().getColor();

However, the second one overwrites the first one(FooB.prototype = new Foo() is cancelled out). Is there any way to fix this problem, or am I going in the wrong direction?

Thanks in advance, sorry for any bad terminology.

tcooc
  • 20,629
  • 3
  • 39
  • 57

3 Answers3

6

Each object can only have one prototype, so if you want to add to the prototype after inheriting (copying) it, you have to expand it instead of assigning a new prototype. Example:

function Foo() {}

Foo.prototype = {
    x: function(){ alert('x'); },
    y: function(){ alert('y'); }
};

function Foo2() {}

Foo2.prototype = new Foo();
Foo2.prototype.z = function() { alert('z'); };

var a = new Foo();
a.x();
a.y();
var b = new Foo2();
b.x();
b.y();
b.z();
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Is there no way to expand the prototype with another object, without overwriting it? – tcooc Jan 20 '11 at 11:50
  • 1
    @digitalFresh: No, there is no way to concatenate objects, so you have to copy each property from one object to the other. That can however be done with a loop. The `jQuery.extend` method does that for example. – Guffa Jan 20 '11 at 12:30
  • @digitalFresh - You can extend it of course as @Guffa wrote. See my answer for more detail (without using jQuery). – gblazex Jan 20 '11 at 12:49
2

One solution would be:

function FooB() {}
var p = new Foo();
p.methodA = function(){...}
p.methodB = function(){...}
p.methodC = function(){...}
...

FooB.prototype = p;

Update: Regarding expanding with an existing object. You can always copy the existing properties of one object to another one:

FooB.prototype = new Foo();
var proto = {
     /*...*/
};

for(var prop in proto) {
    FooB.prototype[prop] = proto[prop];
}

As long as proto is a "plain" object (i.e. that does not inherit from another object) it is fine. Otherwise you might want to add if(proto.hasOwnProperty(prop)) to only add non-inherited properties.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • `proto` can be a "plain" object, but if a third party script augments `Object.prototype` you will end up copying those value to `FooB.prototype`. – gblazex Jan 20 '11 at 12:39
2

You can use an extend function which copies the new members to the prototype object.

function FooB() {}
FooB.prototype = new FooA();

extend(FooB.prototype, {
    /* other methods here */
});

extend

/**
 * Copies members from an object to another object.
 * @param {Object} target the object to be copied onto
 * @param {Object} source the object to copy from
 * @param {Boolean} deep  whether the copy is deep or shallow
 */
function extend(target, source, deep) {
    for (var i in source) {
        if (deep || Object.hasOwnProperty.call(source, i)) {
            target[i] = source[i];
        }
    }
    return target;
}
gblazex
  • 49,155
  • 12
  • 98
  • 91