prototypical inheritance

  • Thread starter srinivas.singanamalla
  • Start date
S

srinivas.singanamalla

Can anyone help here?

I have two classes, Rect and RoundRect.

RoundRect is a subclass of Rect

mstr.chart.Rect = (function(){

function Rect(x, y, w, h) { /* this is the class constructor */
this.x = x;
this.y = y;
this.w = w;
this.h = h;
};

Rect.prototype.toString = function() {
var str = 'x, y: (' + this.x + ',' + this.y + ') w, h : (' +
this.w + ', ' + this.h + ')';
return str;
}

return Rect; })();

mstr.chart.RoundRect = (function() {
function RoundRect(x,y,w,h,arc) {
mstr.chart.Rect.apply(this, arguments);
this.arc = arc;
}

RoundRect.prototype.toString = function() {
return 'testing directly';
}

RoundRect.prototype = new mstr.chart.Rect();

return RoundRect;
})();

-----------------------------------------------------------------------------
When I alert on toString method of RoundRect, it shows me Rect's
toString. What am I doing wrong here?

var myRect = new mstr.chart.RoundRect (0, 0, 2, 2, 0.2);
alert(tooltipRect.toString());

Thanks,
Srini
 
T

Thomas 'PointedEars' Lahn

I have two classes, Rect and RoundRect.

You don't.
RoundRect is a subclass of Rect

It isn't.

http://javascript.crockford.com/javascript.html
mstr.chart.Rect = (function(){

function Rect(x, y, w, h) { /* this is the class constructor */

It isn't. It is the declaration of a method local to the function you are
creating with this lambda FunctionExpression. Properties of the local
Variable Object are usually not available outside their scope (although some
implementations allow that); however, you return a reference to this method,
thereby creating a closure.

Therefore,you can use the returned Function object as constructor of a
prototype object.
this.x = x;
this.y = y;
this.w = w;
this.h = h;
};

Rect.prototype.toString = function() {
var str = 'x, y: (' + this.x + ',' + this.y + ') w, h : (' +
this.w + ', ' + this.h + ')';
return str;
}

return Rect; })();

mstr.chart.RoundRect = (function() {
function RoundRect(x,y,w,h,arc) {
mstr.chart.Rect.apply(this, arguments);
this.arc = arc;
}

RoundRect.prototype.toString = function() {
return 'testing directly';
}

RoundRect.prototype = new mstr.chart.Rect();

First, there is no point in this assignment as it overwrites everything that
was assigned defined before to this object's property. But see below.
return RoundRect;
})();

-----------------------------------------------------------------------------
When I alert on toString method of RoundRect, it shows me Rect's
toString.
[...]
var myRect = new mstr.chart.RoundRect (0, 0, 2, 2, 0.2);
alert(tooltipRect.toString());

(I assume for brevity that `tooltipRect' is a copy-paste error for `myRect',
and that an object reference is the referred object. Also, I omit
`mstr.chart.' as it does not matter here.)

As it should. You assign a new Rect object (below: r) to
RoundRect.prototype. So the prototype chain of RoundRect objects (such as
`myRect' here) looks like

myRect ---> r ---> Rect.prototype ---> Object.prototype ---> ...

when it should look like

myRect ---> RoundRect.prototype ---> Rect.prototype ---> ...

Therefore, myRect.toString refers to Rect.prototype.toString, as `r'
inherits that through *its* prototype chain.
What am I doing wrong here?

IMHO, you do things unnecessarily complicated and thus lose overview.
The above could be rewritten as follows:

function Rect(x, y, w, h)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}

Rect.prototype.toString = function()
{
// or one might employ an sprintf(1) equivalent
var str = new Array(
"x, y: (", this.x, ",", this.y, ") w, h : (",
this.w, ", ", this.h, ")"
).join("");

return str;
};

function RoundRect(x, y, w, h, arc)
{
Rect.apply(this, arguments);
this.arc = arc;
}

// Courtesy of Lasse Reichstein Nielsen
// Message-ID: <[email protected]>
function clone(obj)
{
function Dummy() {}
Dummy.prototype = obj;
return new Dummy();
}

RoundRect.prototype = clone(Rect.prototype);
RoundRect.prototype.toString = function()
{
return 'testing directly';
};

var myRect = new RoundRect(0, 0, 2, 2, 0.2);
window.alert(myRect); /* .toString() is implicit with window.alert() */

However, if you need to retain your object model, you have to switch the
assignments to RoundRect.prototype.toString and RoundRect.prototype. Then
you would still have

myRect ---> r ---> Rect.prototype

as prototype chain, but since r.toString() existed, it would be called
instead of Rect.prototype.toString().

The next step would be to set up a real prototype chain:

RoundRect.prototype = Rect.prototype

However, that would result in

myRect ---> RoundRect.prototype === Rect.prototype ---> ...

and every modification of the RoundRect.prototype object would affect
Rect.prototype as well.

Therefore, the clone() solution I used above, which would result in

myRect ---> RoundRect.prototype ---> Rect.prototype ---> ...

as it was probably intended.


HTH

PointedEars
 
D

dhtmlkitchen

mstr.chart.RoundRect = (function() {
function RoundRect(x,y,w,h,arc) {
mstr.chart.Rect.apply(this, arguments);
this.arc = arc;
}

RoundRect.prototype.toString = function() {
return 'testing directly';
}
// now override the prototype, obliviating the toString method. Oh no!
RoundRect.prototype = new mstr.chart.Rect();

return RoundRect;

})();

Switch them around and it should work:
RoundRect.prototype = new mstr.chart.Rect();
RoundRect.prototype.toString = function() {
return 'testing directly';
}

There are some nice subleties to this approach of extend:
http://developer.yahoo.com/yui/docs/Lang.js.html

The first is that a no-arg constructor is invoked to trigger prototype
inheritance -- not the real constructor, saving you the headache of
unwanted side effects.

Second, they patched around stupid 'ol JScript DontEnum bug.

I mentioned this a few times on YUI team mail (Yahoo internal) and
filed a bug on Y! bugzilla (also internal) and they did it! They
patched for the stupid IE DontEnum bug. Woulda been nice if they'd
made some mention of my name somewhere. It was a pretty clear and
descript bug rep't, too (at least I thought so). I'm my only advocate :
(

I'm not pimping this library, but it is, in my opinion, the best
approach for prototype inheritance). (And I'm a little proud to have
contributed in some slight way to improve the best inheritance
approach).

Garrett
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top