1

I'm trying to simulate inheritance using jquery extend but as far as I could test, it works only with objects.

What I'm trying to accomplish is:

var baseDefinition = function() {
    var self = this;

    self.calc1 =  function() {
        return "something1";
    }

    self.calc2 =  function() {
        return "something2";
    } 

    self.myObject = {
        propA = 100;
        propB = 200;
    };
}

var derivedDefinition = function() {
    var self = this;

    self.calc2 =  function() {
        return "something different from base";
    }

    self.myObject = {
        propB  = 400;
    };            
}

var instance = $.extend(true, {}, baseDefinition, derivedDefinition);

So I would hope to create a new instance from base definition where the derived definitions would be applied to the base ones but neither definitions would be "touched". Is it possible?

I was hoping to avoid any prototype so basicaly I would like to call instance.calc1 or instance.calc2 without knowing wether it was overriten or not.

Edit:

In my example I didn't include any object properties which was what led me to use jquery's extend function. Although both answers solve inner functions "inheritance", it doesn't (obviously) merge object properties like extend does. As a possible solution I'm thinking after I create my instance to loop through the properties of the instance and apply jquery's extend on them. Although this seems inefficient to me, I don't know if you can advise me on another course of action.

4
  • $.extend() only updates keys in one object with the contents of another. If your first object in the chain is a {}, obviously the end result won't be a function. Just use an explicit namespace object or the regular JS OO features. Commented Jul 30, 2013 at 22:49
  • How are you calling these functions? Commented Jul 30, 2013 at 22:56
  • @millimoose I understand what you mean with "namespace" object but that would overwrite the whole function "class" and not it's overrides. If I'm wrong please let me know. With JS OO you mean using prototypes? Commented Jul 30, 2013 at 23:05
  • @DevRios Yes, I mean the mechanism in JS that already provides inheritance instead of trying to roll your own. Commented Jul 30, 2013 at 23:20

2 Answers 2

4

JQuery extend does not create an inheritance hierarchy, so changes you make to base definition AFTER you extend would not be reflected in derived definition. Here's how you can extend the base definition in a way that does reflect later changes down the inheritance hierarchy using Javascript prototypal inheritance:

var baseDefinition = function() {};

baseDefinition.prototype.calc1 =  function() {
    return "something1";
};

baseDefinition.prototype.calc2 =  function() {
    return "something2";
};   


var derivedDefinition = function() {};

derivedDefinition.prototype = Object.create(baseDefinition.prototype);

derivedDefinition.prototype.calc2 =  function() {
    return "something different from base";
};

var instance = new derivedDefinition();
instance.calc1();  // something1
instance.calc2();  // something different from base
Sign up to request clarification or add additional context in comments.

2 Comments

This is an excelent question and it raises a very important topic "Here's how you can extend the base definition in a way that does reflect later changes down the inheritance hierarchy" I will up this as soon as I have enough reputation but in this particular scenario, I want a frozen in time instance.
Real good but not supported in ie < 10, for those see developer.mozilla.org/en-US/docs/Web/JavaScript/…
1

$.extend only works on already existing objects, not on function which will instantiate objects in the (far?) future:

var instance = $.extend(true, {}, new baseDefinition(), new derivedDefinition());

However, you could of course design an extend function that works for constructors and that returns a function:

function extendConstr() {
    var fns = arguments;
    return function newConstr(){
        var self = {};
        for (var i=0; i<fns.length; i++)
            fns[i].apply(self, arguments);
        return self;
    }
}

var extendedFunction = extendConstr(baseDefinition, derivedDefinition);

var instance = extendedFunction();
console.log(instance); // has `calc1` and overwritten `calc2`

Btw, without an extend function you could've done that already manually in the derived constructor:

function derivedDefinition() {
    baseDefinition.call(this/*, arguments */);

    this.calc2 =  function() {
        return "something different from base";
    }
}
console.log(new derivedDefinition) // has a `calc1` as well

4 Comments

I've just tested your approach in jsfiddle and it seems to work very well. I will test a bit more thouroughly using my real definitions.
Don't just test, try to understand it :-) This doc will probably help you…
It's been a few years since I've met Mr Call and Apply but now I understand what you are doing, very smart actually.
If you wouldn't mind reading through my questions's edit, I would appreciate it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.