Inheritance using object prototype

B

burningodzilla

Hi all - I'm preparing to dive in to more complex application
development using javascript, and among other things, I'm having a hard
time wrapping my head around an issues regarding "inheritance" using
the prototype property. I realize there are no classes in JS, that code
therefore lives in objects instead of class definitions, and that
"inheritance" must be achieved prototypically and not classically.
That said, on with the code. Say I have an object I wish to use as a
super type:

function SuperA(name) {
this.name = name;
this.alertName = function() { alert(this.name); }
}

It takes a string in the constructor, assigns it to the name property,
and provides a way to display that name in an alert box, via alertName
method. What I've come to learn is that if I want to create a sub type,
I must assign a new instance of the super type to the prototype of the
sub type. Like so:

function SubA(name) {
//sub type properties
}
SubA.prototype = new SuperA();

This works fine in that when I create an instance of SubA, it
effectively inherits everything from SuperA. What I don't understand is
why this doesn't achieve the same effect:

function SubA(name) {
this.prototype = new SuperA(name);
}

This simply assigns an instance of the super type to the prototype of
the sub type instance in construction, yet if I create an instance and
attempt to call the method:

var supa = new SubA('one');
supa.alertName();

I get a JS error stating that supa.alertName is not a function. Note
that if I augment the the latter constructor to show the memebers in
construction:

function SubA(name) {
this.prototype = new SuperA(name);
for(var m in this.prototype) {
alert(m + ": " + typeof(this.prototype[m]) + ": " +
this.prototype[m]);
}
}

I get two alerts; the first being:

name: string: one

and the second:

alertName: function: function() { alert(this.name); }

I'd appreciate any clarity that is offered. Thanks!
 
V

VK

Hi all - I'm preparing to dive in to more complex application
development using javascript, and among other things, I'm having a hard
time wrapping my head around an issues regarding "inheritance" using
the prototype property.

The first thing you have to do is to read and study
"The JScript Type System, Part Two: Prototypes and constructors"
<http://blogs.msdn.com/ericlippert/archive/2003/11/06/53352.aspx>
by Eric Lippert

Up to date this is the only existing online resource where inheritance
in ECMAScript languages explained both correctly and understandably.
I really don't want to spoil the reading :) but your current problem
arose from the fact that .prototype property _does not_ define
prototype chain for the object it is applied to. It defines prototype
chain for _instances_ created by the given constructor. Search for the
rest in the linked article.

Besides that two other considerations to take into account:
1) Programming in javascript doesn't mean "use prototype only".
Inherited properties and methods are static in Cx sense: it means that
for 100 object instances there will be only one method if it is
inherited over prototype chain. It means that prototype inheritance is
useful only for members where you don't need to store instance-specific
data. If you need members with instance-specific data then use
constructor itself.

2) Code like
function f() {
this.m = function(){alert('Hello');}
}
forms a closure on each invocation. You don't want to form a closure
unless you _want_ to form a closure.
 
J

Julian Turner

Hi all - I'm preparing to dive in to more complex application
development using javascript, and among other things, I'm having a hard
time wrapping my head around an issues regarding "inheritance" using
the prototype property. I realize there are no classes in JS, that code
therefore lives in objects instead of class definitions, and that
"inheritance" must be achieved prototypically and not classically.
That said, on with the code. Say I have an object I wish to use as a
super type:

function SuperA(name) {
this.name = name;
this.alertName = function() { alert(this.name); }
}

It takes a string in the constructor, assigns it to the name property,
and provides a way to display that name in an alert box, via alertName
method. What I've come to learn is that if I want to create a sub type,
I must assign a new instance of the super type to the prototype of the
sub type. Like so:

function SubA(name) {
//sub type properties
}
SubA.prototype = new SuperA();

This works fine in that when I create an instance of SubA, it
effectively inherits everything from SuperA. What I don't understand is
why this doesn't achieve the same effect:

function SubA(name) {
this.prototype = new SuperA(name);
}

This simply assigns an instance of the super type to the prototype of
the sub type instance in construction, yet if I create an instance and
attempt to call the method:

var supa = new SubA('one');
supa.alertName();

I get a JS error stating that supa.alertName is not a function. Note
that if I augment the the latter constructor to show the memebers in
construction:

function SubA(name) {
this.prototype = new SuperA(name);
for(var m in this.prototype) {
alert(m + ": " + typeof(this.prototype[m]) + ": " +
this.prototype[m]);
}
}

I get two alerts; the first being:

name: string: one

and the second:

alertName: function: function() { alert(this.name); }

I'd appreciate any clarity that is offered. Thanks!

Hi

Three points:-

1. In very simple terms, the "prototype" property used for inheritance
must usually be property of the Function you are using as a constructor
function.

When you create an Object with "new SubA", the Object you create does
not itself does not itself give you express access to the "prototype"
used in the inheritance chain through a "prototype" property.

Having said that, in Firefox (and perhaps other browsers, excluding IE)
you can access this prototype through the "__proto__" property. See :
http://www.webreference.com/js/column79/6.html

2. When you when you call "new SubA", the "this" value refers to the
Object you are creating, not the SubA Function.

So

"this.prototype = new SuperA(name);"

effectively creates a new dynamic property, called "prototype", on your
Object; but which has nothing to do with the prototype used in the
inheritance chain.

3. I have no idea what would happen if you called "this.__proto__ =
new SuperA(name)".

Regards

Julian Turner
 
C

chrislewis

Thanks for the info - it has been very helpful. VK I digested the
article you liked - it was also quite illuminating - much appreciated.
I have a comment regarding one of your points:
Inherited properties and methods are static in Cx sense: it means that
for 100 object instances there will be only one method if it is
inherited over prototype chain. It means that prototype inheritance is
useful only for members where you don't need to store instance-specific
data. If you need members with instance-specific data then use
constructor itself.

That doesn't seem to be entirely correct - at least not the part about
static in a Cx sense. If I declare a super type with two methods on the
Function:

function SuperA() {}
SuperA.getName = function() { return this.name; }
SuperA.setName = function(n) { this.name = n; }

and then a sub type with this as its prototype:

function SubA(n) {
this.name = typeof(n) == 'undefined' ? '' : n;
}
SubA.prototype = SuperA;

var supa = new SubA('test 1-1');
alert(supa.getName());
supa.setName('test 1-2');
alert(supa.getName());

var supa2 = new SubA('test 2-1');
alert(supa2.getName());
supa2.setName('test 2-2');
alert(supa2.getName());
//verify that 2 different instances have unique data and thus unique
members
alert(supa.getName());

Then the inherited methods act on the instance data, since the methods
access this.name. So in that since they differ from static methods as
they can indeed access instance data (I confirmed creating multiple
instances have unique members). If however the methods are declared
without accessing this.x:

function SuperA() {
this.name = 'super';
}
SuperA.getName = function() { return name; }
SuperA.setName = function(n) { name = n; }

Then the methods all access the singular name property of the SuperA
constructor.

Point being that methods inherited on the prototype chain can access
instance data via this.

Regarding your point on closures - I incorrectly (due to my oo
background) assumed that declaring methods like that would pass them on
to inheriting types. As you pointed out, only members on the Function
prototype get propagated. However it seems that adding methods to the
Function prototype that access instance members via this is a workable
way to pass on methods sub types. Are you under this impression?

Thanks again for the discussion and info!
 
J

John G Harris

(e-mail address removed) writes

What I've come to learn is that if I want to create a sub type,
I must assign a new instance of the super type to the prototype of the
sub type. Like so:

function SubA(name) {
//sub type properties
}
SubA.prototype = new SuperA();
<snip>

I'm afraid you've learnt a messy way of doing it.

Suppose you have three constructors A, B, and C, and you want C
instances to derive from B and B from A. When you create a C instance by
doing

var cobj = new C(x, y, z);

you want cobj to have a prototype chain holding all the methods of A, B,
and C objects, and cobj itself to hold all the data fields appropriate
to A, B, and C objects. In javascript you, yourself, have to do the work
of making this happen :-(

The job of the objects in the prototype chain is to hold methods, not
data. To do it cleanly you don't want these objects to be A, B, or C
instances : they are different types. You could call them proto_A,
proto_B, and proto_C instances, and construct them with their own
special constructors.

John
 
C

chrislewis

Hi John - thanks for the comments. Thus far I've learned what you said,
and have been assigning Function definitions (as opposed to instances)
to prototypes of sub types. The one thing that I haven't found that
you've said is that for each instance you must create all it's data
members in the constructor. Following is a snip of code I've been
documenting for my learning purposes - please tell me if feel my
findings are invalid:

function SuperA() {
/*
* Any members defined here will be available to instances created
* via new SuperA(). They are object instance members, NOT Function
* members, and therefore will not be added into the prototype chain
* when SuperA is set as the prototype of other Functions (sub types).
*/
}
/*
* These methods access this.name, and so access the member name
* in the context of the current object instance. This seems to
* effectively allow sub types to inherit these methods and have
* them operate on their instance members.
*
* Note that if a sub type doesn't explicitly declare a this.name
* member in its constructor, the memeber will be undefined. Calling
* [instance].setName on the instance will add this member to it.
*/
SuperA.getName = function() { return this.name; }
SuperA.setName = function(n) { this.name = n; }
/*
* Note that the data member (sname) declared as a Function member of
* SuperA will be propagated to sub type instances. Each sub type
instance
* will have it's own copy (at least of the sname data member), as
proven
* below.
*/
SuperA.sname = 'super';
SuperA.getSname = function() { return this.sname; }


Lastly, regarding your statment:
The job of the objects in the prototype chain is to hold methods, not
data. To do it cleanly you don't want these objects to be A, B, or C
instances : they are different types. You could call them proto_A,
proto_B, and proto_C instances, and construct them with their own
special constructors.

Would you mind providing a simple example?

Much apperciated!
 
J

John G Harris

Hi John - thanks for the comments. Thus far I've learned what you said,
and have been assigning Function definitions (as opposed to instances)
to prototypes of sub types. The one thing that I haven't found that
you've said is that for each instance you must create all it's data
members in the constructor. Following is a snip of code I've been
documenting for my learning purposes - please tell me if feel my
findings are invalid:

function SuperA() {
/*
* Any members defined here will be available to instances created
* via new SuperA(). They are object instance members, NOT Function
* members, and therefore will not be added into the prototype chain
* when SuperA is set as the prototype of other Functions (sub types).
*/
}
/*
* These methods access this.name, and so access the member name
* in the context of the current object instance. This seems to
* effectively allow sub types to inherit these methods and have
* them operate on their instance members.
*
* Note that if a sub type doesn't explicitly declare a this.name
* member in its constructor, the memeber will be undefined. Calling
* [instance].setName on the instance will add this member to it.
*/
SuperA.getName = function() { return this.name; }
SuperA.setName = function(n) { this.name = n; }
/*
* Note that the data member (sname) declared as a Function member of
* SuperA will be propagated to sub type instances. Each sub type
instance
* will have it's own copy (at least of the sname data member), as
proven
* below.
*/
SuperA.sname = 'super';
SuperA.getSname = function() { return this.sname; }

To tell the truth, I'm not sure what you are trying to say here. Have
you tried drawing a picture of an instance and its prototype chain? Show
where you would like to put the things that are common to all instances,
e.g methods, and where you would like to put the things that can be
different in each instance, e.g data values.

If you have put the same thing in lots of different places, or have
things that are never going to be used, then you've done it in a messy
way.

Lastly, regarding your statment:


Would you mind providing a simple example?

<URL:http://www.jgharris.demon.co.uk/jsfeats/JSfeats.html#seca1p1>

John
 

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,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top