Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a function in Javascript to Generate Noninstantiated Functions

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!

like image 613
ebdavis Avatar asked Oct 03 '22 00:10

ebdavis


2 Answers

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
like image 139
Givi Avatar answered Oct 13 '22 11:10

Givi


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!

like image 45
micnic Avatar answered Oct 13 '22 10:10

micnic