Reputation: 4611
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
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
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