javascriptoopinheritanceapplyfunction-constructor

JS OOP. Inheritance and apply() function. Why it doesn't work?


I have such example.

function Bar() {
    this.barVal = "BarValue";
}

function Foo() {
    this.fooVal = "FooValue";
    Bar.apply(this, arguments);   // here I use apply() to get access everything in Bar from Foo;
}
var barObj = new Bar;
var fooObj = new Foo;

alert(fooObj.barVal);     // the output is `BarValue`

Now I want the same way get access to everything in Foo from Bar. I modify my code:

function Bar() {
    this.barVal = "BarValue";
    Foo.apply(this, arguments);   // I add the same line of code, just change names
}

function Foo() {
    this.fooVal = "FooValue";
    Bar.apply(this, arguments);   // and also leave it here because I want previous functionality too
}
var barObj = new Bar;
var fooObj = new Foo;

alert(fooObj.barVal);     
alert(barObj.fooVal);     // there is no any output for both

But there is no any output. I fact some mistake occurs. When I hide Foo.apply(this, arguments); under the comment, the call alert(fooObj.barVal); works again. When I check it like this:

function Bar() {
    this.barVal = "BarValue";
    try {
        Foo.apply(this, arguments);
    }
    catch(e) {
        alert(e);
    }
}

it even stops browser work (I use Chrome so whole blaсk screen with pixel folder on it appears). And in alert-window it writes RangeError: undefined

BUT as I have alert calls in this sequence

alert(fooObj.barVal);     
alert(barObj.fooVal);

the second alert shows exactly what I'm waiting for from it - it shows BarValue.

Why apply() doesn't work when I duplicate it in Bar? Is it possible somehow to make such kind of gates between two functions?


Solution

  • apply calls the function, using whatever this you specify.

    Think about that for a second. If Foo calls Bar, and Bar calls Foo, then you end up with infinite recursion. You need some kind of way to say "don't call Foo again". Or at the very least, Foo needs to be able to see "hey, i've already been called once; don't do anything this time".

    Truth be told, though, the fact that you need to do any of that smells. You generally don't want circular dependencies like that; if the two thingies are so intertwined that they need each other's functionality in order to work, it sounds like you might be able to split off the intertwined stuff into a separate type and use both Foo and Bar from there, or have both inherit from it, or something. But i'd need to see more of the design in order to say anything specific about any of that.