5

I have the following code:

function Rune(){
    this.subSpells = [];
}
function Modifier(){
    this.type = "modifier";
}
Modifier.prototype = new Rune();

function RuneFactory(effect, inheritsFrom, initialValue){
    var toReturn = function(){}; 
    toReturn.prototype = new inheritsFrom();
    toReturn.prototype.subSpells[effect] = initialValue;
    return toReturn;
}

Duration = RuneFactory("duration", Modifier, 1);
Quicken = RuneFactory("quicken", Modifier, 1);

x = new Duration();
y = new Quicken();

Both x.subSpells.duration and x.subSpells.quicken equal 1. Same with y. I want x.subSpells.quicken and y.subSpells.duration to be undefined.

If I do the following for the Duration and Quicken definitions, I get the behaviour I want.

Duration = RuneFactory("duration", Rune, 1);
Quicken = RuneFactory("quicken", Rune, 1);

I think there is a problem with double inheritance. Can anyone tell me how to change my RuneFactory code such that it works with double inheritance and/or explain what's breaking? If at all possible, I would like to avoid using a framework.

Thank you!

6
  • 4
    Add following line in the Modifier function Rune.apply(this, arguments);, since subSpells defined at prototype level, all instance of Rune refer to same object. Commented Jan 2, 2014 at 10:02
  • 2
    +1 However, be aware that the Rune constructor will be called twice, once to populate the prototype of Modifier, and once for the instanciation. You should replace Modifier.prototype = new Rune() with Modifier.prototype = Object.create(Rune.prototype) to avoid this. Note : Object.create is a recent feature, go here for a workaround in old browsers if needed : stackoverflow.com/a/20879584/1636522. Commented Jan 2, 2014 at 10:07
  • 1
    Side note: you are specifying a string index to an array--shouldn't subspells be an object instead? Commented Jan 2, 2014 at 10:10
  • I cannot reproduce your problem. In either way, I get a value of 1. And you are explicitly setting it to 1 with the initialValue. So why do you expect it to be undefined. Or am I missing something? Commented Jan 2, 2014 at 10:12
  • The inheritance looks fine to me - whether you pass in Rune or Modifier to inherit from, the result still has a subSpells property. Commented Jan 2, 2014 at 10:16

2 Answers 2

3

Add following line in the Modifier function Rune.apply(this, arguments);, since subSpells defined at prototype level, all instance of Rune refer to same object.
And, change type of subSpells from array to object.

As mentioned by wared would be better if you use Parasitic Combination Inheritance Pattern.

"I think there is a problem with double inheritance" - No!

At first, there's no such thing as double inheritance, you have same problem as with Modifier constructor, your instances refer to same subSpells object (Array in your case. read about Primitive value vs Reference value or References and Values it's about .NET, but basic principles are the same in programming).

Look at How does JavaScript .prototype work?


Look at jsFiddle

function inheritPrototype(subType, superType) {
    var prototype = Object.create(superType.prototype, {
        constructor: {
            value: subType,
            enumerable: true
        }
    });

    subType.prototype = prototype;
}

function Rune() {
    this.subSpells = {};
}

function Modifier() {
    Rune.apply(this, arguments);
    this.type = "modifier";
}

inheritPrototype(Modifier, Rune);

function RuneFactory(effect, inheritsFrom, initialValue) {
    function toReturn() {
        inheritsFrom.apply(this, arguments); // you should bind this
        this.subSpells[effect] = initialValue;
    }
    inheritPrototype(toReturn, inheritsFrom);
    return toReturn;
}

Duration = RuneFactory("duration", Modifier, 1);
Quicken = RuneFactory("quicken", Modifier, 1);

x = new Duration();
y = new Quicken();

console.log(x.subSpells.duration); // 1
console.log(x.subSpells.quicken); // undefined

console.log(y.subSpells.duration); // undefined
console.log(y.subSpells.quicken); // 1
Sign up to request clarification or add additional context in comments.

Comments

1

The correct way to inherit in JavaScript is:

function Parent(arg1, arg2) {
    // Do something
}

function Child(arg1, arg2) {
    Parent.call(this, arg1, arg2); // or Parent.apply(this, arguments)
}

Child.prototype = Object.create(Parent.prototype, {
    constructor: {
        value: Child
    }
});

So you will need something like this:

function Rune(){
    this.subSpells = {};
}

function Modifier(){
    Rune.apply(this, arguments);
    this.type = "modifier";
}

Modifier.prototype = Object.create(Rune.prototype, {
    constructor: {
        value: Modifier
    }
});

function RuneFactory(effect, inheritsFrom, initialValue){
    var toReturn = function(){}; 
    toReturn.prototype = Object.create(inheritsFrom.prototype, {
        constructor: {
            value: Modifier
        }
    });
    toReturn.prototype.subSpells = {};
    toReturn.prototype.subSpells[effect] = initialValue;
    return toReturn;
}

Duration = RuneFactory("duration", Modifier, 1);
Quicken = RuneFactory("quicken", Modifier, 1);

x = new Duration();
y = new Quicken();

NOTE: in your question .subSpells is an array but you assign an member as it would be an object!

Comments

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.