pQuestions123
pQuestions123

Reputation: 4611

javascript: writing callable objects

Note: I simplified the logic greatly for this example. Please assume that I need the functions, closures etc. described.

Recently, I wrote a class:

function Foo () {
    var self = this;
    self.number = 0;
    self.methodA = methodA;

    /////

    function methodA () {
        self.number++;
    }
}

then, I decided I wanted to do the following:

function Bar() {
    Foo.call(this);

    this.methodA = methodA;

    var cleanFoo = new Foo();
    ////

    function methodA () {
        this.number = cleanFoo.methodA.call(this);
    }
}

Bar.prototype = Foo;
Bar.prototype.constructor = Bar;

Basically, I would like Bar to inherit from Foo, to override methodA but call Foo's methodA from the overridden one.

I realized though, that, in its current state, I couldn't call Foo's methodA because it was referencing self which, when I call it from a clean object, would reference the clean object even though I passed in a different context.

I decided that the way to solve this is to rewrite the Foo like this:

function Foo () {            
        this.number = 0;
        this.methodA = methodA;

        /////

        function methodA () {
            var self = this; //assume I need this closure in methodA for logic that has been edited out.
            self.number++;
        }
}

However, then, I realized that I wanted to add methodB to Foo which calls methodA:

function Foo () {
    this.number = 0;
    this.methodA = methodA;

    /////

    function methodA () {
        var self = this; //assume I need this closure in methodA for logic that has been edited out.
        self.number++;
    }

    function methodB () {
            methodA();   
           return this.number;
        }
    }

but I realized that that when I did this that self in methodA would be methodB. I solved this by changing the call in methodB to this.methodA() which ensures that the context in methodA is the object itself and not methodB.

Am I correct? Is this the way to build a class so that its methods are callable? Am I missing something obvious.

Upvotes: 0

Views: 64

Answers (2)

David Biga
David Biga

Reputation: 2801

You are on the right track! jfriend00 did a great job explaining. Here is my answer to this anyways.

You have a parent class (Bar) that is handling the core elements of your application. Lets say you want to increase a number for a specific part of the application, you might make another class called (Foo).

Heres how that might look:

var Bar = Class.create({
    initialize: function() {

      // initialize any variables      
      this.foo = new Foo();       
      // call foo 
      this.incrementFooNumber();

    },
    incrementFooNumber: function() {
      this.foo.incrementNumber();
    }
});

var Foo = Class.create({
        initialize: function() {
          // initialize any variables 
          var number = 0;
          // assign locally
          this.number = number;      

        },
        incrementNumber: function() {
          this.number++;
        }
    });

You can easily start Bar by calling: var bar = new Bar(); Now you can see that we initiate Bar and inside Bar is where we assign locally the Foo instance and than call incrementFooNumber which calls the method incrementNumber inside Foo.

Upvotes: 0

jfriend00
jfriend00

Reputation: 707876

If you want to call a parent's method that is defined on the prototype from an overriden subclass method, you can access the prototype directly.

If Bar is a subclass of Foo, then you can call the Foo version of the method like this:

Bar.prototype.methodB = function () {
    // call base class implementation
    Foo.prototype.methodB.call(this);
}

If the method is not defined on the prototype but is set in the constructor, then you have to save the prior reference to the method before you override it in the derived constructor.

function Bar() {
     Foo.call(this);

     var oldMethodB = this.methodB;
     this.methodB = function() {
         // call base class implementation
         oldMethodB.call(this);
     }
}

You can use either .call() or .apply() to set the appropriate value of this when calling the base class method.

I'm not sure if this is a point of confusion for you or not, but keep in mind that there's only one this value for derived and base class instance. Some people get confused thinking there's a different this for the Bar component of an object versus the Foo component of the object. That is not the case. It's one object with properties from each class on the same object. So, when you want to call a Foo method with the appropriate this value, you can use the this value from an appropriately called Bar method.


In addition, this line is not correct:

Bar.prototype = Foo;

That should be:

Bar.prototype = Object.create(Foo.prototype);

Upvotes: 3

Related Questions