Search code examples
javascriptinheritanceprototypeturbulenz

How do I inherit a function from a base object and overwrite it in javascript


What I am trying to do is have a child object provide its own implementation for a function defined in a base object. As far as I've understood so far prototypes are the best (only!) way to go about doing this.

Note also that I am currently developing using the game engine: Turbulenz and as such I am trying to follow / stick to their style as closely as possible. In the engine "classes"/objects are defined and created in the following manner

function baseObject() { }
baseObject.prototype = 
{
    myMember1: 1,
    myMember2: 2,

    myMethod: function myMethodFn() {
        return this.myMember1 + this.myMember2;
    }
}

baseObject.Create = function baseObjectCreateFn
{
    var o = new baseObject();
    return o;
}

This would allow me to do the following

var anObject = baseObject.Create();
var someValue = anObject.myMethod(); // should return 3

What I would like to be able to do now is to create a new object that inherits all the properties of baseObject while allowing me to overwrite its myMethod function to for example subtract the two member values instead of add.

Would I be correct in saying that I will have to create another object then alter its prototype? The part thats throwing me most is that the definition of the baseObject's prototype is defined as an object literal and so I'm unsure of the syntax to overwrite one of its members, i.e. would the following be valid or not? :

function childObject() {}

childObject.prototype = baseObject.Create() // would this inherit from baseObject?
// or should it be: childObject.prototype = new baseObject();

// this is the part thats confusing me as the syntax 
// doesn't quite match the original base objects prototype 
// syntax and I'm unsure if that will matter
childObject.prototype.myMethod = function myMethodFn() {
    return this.myMember1 - this.myMember2;
} 

childObject.Create = function childObjectCreateFn
{
    var o = new childObject();
    return o;
}

var aChildObject = childObject.Create()
var anotherValue = aChildObject.myMethod() // would this return -1 as expected?

To summarise I'm trying to create an object that will overwrite a function that exists in a base object by inheriting the function from the base object and changing it, how do I do this? Thanks for your time.


Solution

  • You have it correct.

    As for the syntax confusion, there is no real difference between

    thing.prototype.myMethod = function () { ... }
    

    and

    thing.prototype = { myMethod: function() { ... } };
    

    except for the fact that in the second one you are setting the prototype all at once (to an object literal), and if you do it again, you'll overwrite the prototype all at once with a new object literal. But because it is an object literal, you can't do inheritance this way (everything declared with naked braces { ... } is just an instance of Object of no special type). If you stick with the first syntax you'll always be ok.

    Note that when you put:

    childObject.prototype.myMethod = function myMethodFn() { ... }
    

    The part where you put myMethodFn is actually ignored. The function is named myMethod by the fact that this is where you assigned it.

    Similarly, where you have

    childObject.Create = function childObjectCreateFn
    

    you don't need childObjectCreateFn (it's ignored), and you need to put parentheses () somewhere after function or it's a syntax error.

    Moving on to the reason why this works, every created object in Javascript has a prototype. When you call a method on that object, it first looks inside the object itself to see if a key corresponding to the name of the method exists. If not, it looks in the prototype object for the same thing, and if it's not there, it goes to that object's prototype, and so on, until it gets to the root Object, which has no prototype.

    In this way you can override an implementation merely by naming it the same thing, but having it appear earlier in the prototype chain. That's exactly what you're doing on childObject. It retains the functionality of baseObject because you created an instance of baseObject to serve as childObject's prototype. Then you augmented childObject's prototype with a new method of the same name, but one that comes earlier in the prototype chain.