Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

JavaScript and inheritence

5 views
Skip to first unread message

Vincent van Beveren

unread,
Jul 8, 2004, 10:02:44 AM7/8/04
to
Hi everyone,

I have the following code using inheritence The important part is the
function getName(). The result should alert 'John Doe':

function First(name) {
this.name = name;

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

function Doe(firstName) {
this.base = First;
this.base(firsName);

this.getName = function() {
return this.base.getName()+' Doe';
}
}
d = new Doe('John');
alert(d.getName());

But it doesn't work, because it says this.base.getName() is not a function.

That could be, but how can I still accompish this? There is no
this.super or something as far as I know. Is there a nice way of
doing this. I figured I could do the following in Doe:

this.getParentName = this.getName;
this.getName = function() {
return this.getParentName()+' Doe';
}

But thats not very neat because when I inhert from this object and I
apply the same trick to that new object then I'll create neverending
recursion, finally causing a stackoverflow. Anyone know any other way?

Thanks in advance,
Vincent

Lee

unread,
Jul 8, 2004, 11:54:41 AM7/8/04
to
Vincent van Beveren said:
>
>Hi everyone,
>
>I have the following code using inheritence The important part is the
>function getName(). The result should alert 'John Doe':
>
> function First(name) {
> this.name = name;
>
> this.getName = function() {
> return this.name;
> }
> }
>
> function Doe(firstName) {
> this.base = First;
> this.base(firsName);

1. "firsName" is undefined. You should always copy and paste
tested code into your post, to avoid typos in your example
that aren't part of your original problem.

2. What do you intend for that line to do? You're invoking
a constructor without the "new" keyword.

>
> this.getName = function() {
> return this.base.getName()+' Doe';
> }

At this point, this.base is a reference to the First function,
not an object of type First.

It seems as if you want your function Doe() to be:

function Doe(firstName) {
this.base = new First(firstName);


this.getName = function() {
return this.base.getName()+' Doe';
}
}

Nothing is really being inherited here, though.
It's just encapsulating an object.

John G Harris

unread,
Jul 8, 2004, 3:14:22 PM7/8/04
to
In article <40ed535b$0$6968$e4fe...@news.xs4all.nl>, Vincent van
Beveren <vin...@provident.remove.this.nl> writes

>Hi everyone,
>
>I have the following code using inheritence
<snip>

>But it doesn't work, because it says this.base.getName() is not a function.
<snip>

Maybe this example

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

will give you some ideas.

John
--
John Harris

Vincent van Beveren

unread,
Jul 9, 2004, 4:02:14 AM7/9/04
to
> 1. "firsName" is undefined. You should always copy and paste
> tested code into your post, to avoid typos in your example
> that aren't part of your original problem.

Oops, yeah, I made some modifications for clearity. Apparently I
forgot to test it. This gives the error I'm having trouble with.

<SCRIPT LANGUAGE="JavaScript">


function First(name) {
this.name = name;

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

function Doe(firstName) {
this.base = First;

this.base(firstName);

this.getName = function() {
return this.base.getName()+' Doe';
}
}

d = new Doe('John');
alert(d.getName());

</SCRIPT>

> 2. What do you intend for that line to do? You're invoking
> a constructor without the "new" keyword.
>

[...]


>
> Nothing is really being inherited here, though.
> It's just encapsulating an object.
>

No, base is an official part of the JavaScript specification. Try this:

function Foo() {
this.test = 'Im from the base class';
}

function Bar() {
this.base = Foo;
this.base();
}

b = new Bar();
alert(b.test);

Thanks,
Vincent

Vincent van Beveren

unread,
Jul 9, 2004, 4:27:15 AM7/9/04
to

John G Harris wrote:

> Maybe this example
>
> <URL:http://www.jgharris.demon.co.uk/jsfeats/JSfeats.html#seca1p1>
>
> will give you some ideas.
>

Thanks, I looked through the code, but looking through the code I come
to the conclusion that there is no way to overwrite methods in JS.

The trick they use for the toString method is the following:

function Parent() {

this.parentToString = function()
return "parent";
}

this.toString = this.parentToString;
}

function Child() {
this.base = Parent;
this.base();

this.childToString = function() {
return this.parentToString()+" and child";
}

this.toString = this.childToString
}

But thats a work-around. It would save a lot of trouble if there was
a simpleler way of using inherience:

function Parent() {

this.foo = "bar";

this.toString = function() {
return "parent";
}

}

function Child() {
this.base = new Parent();

this.toString = function() {
return this.base.toString()+" and child";
}
}

c = new Child();
alert(c.foo);
alert(c.toString());

The first alert would give "bar", the second "parent and child"

could anyone tell me why this is impossible in JavaScript? Or why this
hasn't been done yet?

Thanks,
Vincent

Lasse Reichstein Nielsen

unread,
Jul 9, 2004, 7:20:16 AM7/9/04
to
Vincent van Beveren <vin...@provident.remove.this.nl> writes:

> Thanks, I looked through the code, but looking through the code I come
> to the conclusion that there is no way to overwrite methods in JS.

Interesting conclusion.

> The trick they use for the toString method is the following:
>
> function Parent() {
> this.parentToString = function()
> return "parent";
> }


Define function, assign it to current object's parentToString property ...

> this.toString = this.parentToString;

... and assign same function to the toString property.

> }
>
> function Child() {

> this.base = Parent;
> this.base();

These two lines is and idiom for using the Parent function to initialize
the CHild object being created. It doesn't create a Parent object, and
it uses the new object, this, as the "this" for the Parent function.

> this.childToString = function() {
> return this.parentToString()+" and child";

So this works, because "this" has a parentToString method.

>
> But thats a work-around. It would save a lot of trouble if there was
> a simpleler way of using inherience:

There is:
---
function Parent(){};
Parent.prototype.toString = function() { return "parent"; };

function Child(){};
Child.prototype.toString = function() {
return Parent.prototype.toString() + " and child";
};
---

> function Parent() {
> this.foo = "bar";
> this.toString = function() {
> return "parent";
> }
> }
>
> function Child() {
> this.base = new Parent();

So here you create a new Parent *object*. You create one for each
Child object. You can reference it, but it's just part of the Child
object.

> this.toString = function() {
> return this.base.toString()+" and child";
> }
> }
>
> c = new Child();
> alert(c.foo);
> alert(c.toString());
>
> The first alert would give "bar", the second "parent and child"

No, the first alert should give "udefined", because the Child object
doesn't have a "foo" property. It has a "base" property, which is a
Parent and which therefore has a "foo" property, but the Child object
doesn't have a "foo" property itself.

> could anyone tell me why this is impossible in JavaScript?

No, because it is.

> Or why this hasn't been done yet?

It has.


Ok, Javascript doesn't have *class* inheritance, mainly because it doesn't
have classes.

A Javascript constructor is just a function. When creating a new object
with the "new" operator on a constructor function "Foo", you
1: create a new object,
2: make its prototype link point to the object Foo.prototype,
3: execute Foo with "this" referring to the new object, and
4: if Foo returns an object, the new operator evalutes to that, otherwise \
it evaluates to the newly constructed object.

That is, inheritance in Javascript is between objects (the prototype
objects), not classes (which doesn't exist) or functions (which merely
acts as initializers and holders of the prototype object).

Example:
---
function Foo(){};
Foo.prototype.baz = "foo";
function Bar(){};
Bar.prototype.baz = "bar";

var foo = new Foo();
var bar = new Bar();

alert(foo.baz); // foo
alert(bar.baz); // bar

Foo.prototype.baz = "arglebargle";

alert(foo.baz); // "arglebargle" - dynamic inheritance

alert(foo instanceof Foo); // true
alert(foo instanceof Bar); // false
alert(bar instanceof Foo); // false
alert(bar instanceof Bar); // true

// swap prototype
var tmp = Foo.prototype;
Foo.prototype = Bar.prototype;
Bar.prototype = tmp;

// and the surprice
alert(foo instanceof Foo); // false
alert(foo instanceof Bar); // true - because Bar.prototype is foo's proto
alert(bar instanceof Foo); // true
alert(bar instanceof Bar); // false

alert(foo.baz); // arglebargle
alert(bar.baz); // bar
---
As the "surprice" shows, the inheritance/instanceof relation follows
only the prototype object of the constructor function, not the function
itself. The function merely holds the prototype, and when a new object
is created, the function is called to initialize the object.

So, there is no class based inhertance. So, what is it that you are
trying to achieve, exactly? Because we can emulate most of it, we just
need to know which part is needed. Douglas Crockford has a page on
how to emulate different kinds of inheritance in Javascript:
<URL:http://www.crockford.com/javascript/inheritance.html>


What you seem to want is to call the Parent constructor to initialize
the Child object as well as do the initialization of the Child.
You also want to refer to the Parent object's functions when the
Child overrides them.

For that, you can just do:

---
function Parent() {...}
Parent.prototype.xxx = ...;

function Child() {
// call Parent initialization
this.parentConstructor = Parent;
this.parentConstructor();
delete this.parentConstructor;

// remember parent version
this.parentToString = this.toString();
// use it
this.toString = function() {
this.parentToString() + " and child";
}
}
---

However, that doesn't inherit the properties on the Parent.prototype
object.

The way I do that is:

---
function inheritObject(object) {
function Dummy(){};
Dummy.prototype = object;
return new Dummy();
}

function Child() {
Parent.call(this); // simpler than assigning it, calling it, and
// removing it again, but only works in modern browsers
// child initalization;
}
Child.prototype = inheritObject(Parent.prototype);
---

Example:
---
function Parent(i) { this.i = i; }
Parent.prototype.toString = function() { return "parent["+this.i+"]"; };
Parent.prototype.incI = function () { this.i++; };

function Child(i, j) {
Parent.call(this, i);
this.parentToString = Parent.prototype.toString;
this.j = j;
}
Child.prototype = inheritObject(Parent.prototype);
Child.prototype.incJ = function () { this.j++; };
Child.prototype.toString = function() {
return this.parentToString() + " and child[" + this.j + "]";
};
---

Now test this:
---
var p = new Parent(42);
var c = new Child(37,87);
alert(p.toString()); // parent[42]
alert(c.toString()); // parent[37] and child[87]
p.incI();
alert(p.toString()); // parent[43]
alert(c.toString()); // parent[37] and child[87]
c.incI();
alert(p.toString()); // parent[43]
alert(c.toString()); // parent[38] and child[87]
c.incJ();
alert(c.toString()); // parent[38] and child[88]
alert(p.incJ); // undefined
---
That is, the child has inherited the "incI" method, and the toString
method has been assimilated :)

/L
--
Lasse Reichstein Nielsen - l...@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

John G Harris

unread,
Jul 9, 2004, 3:47:47 PM7/9/04
to
In article <40ee563b$0$14941$e4fe...@news.xs4all.nl>, Vincent van
Beveren <vin...@provident.remove.this.nl> writes
>
>

>John G Harris wrote:
>
>> Maybe this example
>> <URL:http://www.jgharris.demon.co.uk/jsfeats/JSfeats.html#seca1p1>
>> will give you some ideas.
>>
>
>Thanks, I looked through the code, but looking through the code I come
>to the conclusion that there is no way to overwrite methods in JS.
<snip>

I think you've got it the wrong way round. It's all too easy for Child's
toString method to hide Parent's toString. The difficult bit is finding
a way for a Child to call the Parent's toString.

In C++ you would write Parent::toString, and something similar in other
languages. But this won't work in javascript because objects don't have
class names, so there isn't a name you could put in front of the :: .

Javascript is very different from other languages. Learn to do things
the javascript way - it's better than wishing for VBScript or C# :-)

John

PS My spelling checker wanted to change VBScript to javascript !
--
John Harris

Vincent van Beveren

unread,
Jul 12, 2004, 5:00:11 AM7/12/04
to
Hi Lasse,

thanks for your insightful posting. I'll need to reread it a few times
in order to make it all clear to me.

> So, there is no class based inhertance. So, what is it that you are
> trying to achieve, exactly? Because we can emulate most of it, we just
> need to know which part is needed.

Some kind of class-like inhertence, but not really with classes. I just
would like to create a one-on-one parent to child relationship. With
prototypeing it seems that I can only assign one parent to a group of
child objects. But that means that all childs have the same instance of
a parent.

The problem is that I have an object and I want to create a new one
extending the capabilities of the current object. However, each
instance of the extended object, needs to have it own instance of
the parent object.

I thought 'base' was a special keyword, but as I understand it, I can
just as wel do

function Y() {
this.blah = X;
this.blah();
delete this.blah();
}

I still don't understand why its impossible to assign a parent to a
child object as being really a part of the JavaScript language. Though
now I guess I know enough to make some sort of inhertence, I'm still not
convinced that there is a good way of doing it. For me a good way of
doing it would be what I described in my previous posting and is
somewhat like this:

function Parent() {
this.y = 123;
this.x = function x() {
alert('x');
}
}

function Child() {
this.parent = new Parent(); // now there is a parent
// child relationship.
}

c = new Child();
c.x(); // would alert 'x';

this.parent being reserved for referencing to the parent of the object.

So, this would not mess things up:

function SubChild() {
this.parent = new Child();
}

sc = new SubChild();
alert(sc.y); // would alert 123

Its a kind of prototyping but then not based on the function but on the
instance of the object itself.

Anyway, thanks for the post, and I think its enough to help me further,
but I still have the opinion that iheritence in JavaScript is more
complecated than it would have to be. Maybe I should join the ECMA ;)

Thanks,
Vincent

Thomas 'PointedEars' Lahn

unread,
Jul 12, 2004, 5:56:33 AM7/12/04
to
Lasse Reichstein Nielsen wrote:
> [...]

> However, that doesn't inherit the properties on the Parent.prototype
> object.
>
> The way I do that is:
>
> ---
> function inheritObject(object) {
> function Dummy(){};
> Dummy.prototype = object;
> return new Dummy();
> }
>
> function Child() {
> Parent.call(this); // simpler than assigning it, calling it, and
> // removing it again, but only works in modern browsers
> // child initalization;
> }
> Child.prototype = inheritObject(Parent.prototype);
> ---

Can you provide a reasonable explanation and/or an example which
proves that the inheritObject() method is needed? AFAIS it is
not,

function Child() {
Parent.call(this);
// child initalization;
}
Child.prototype = new Parent();

would suffice. In your example, everything works OK with

function Parent(i) { this.i = i; }
Parent.prototype.toString = function() { return "parent["+this.i+"]"; };
Parent.prototype.incI = function () { this.i++; };

function Child(i, j) {
Parent.call(this, i);
this.parentToString = Parent.prototype.toString;
this.j = j;
}

Child.prototype = new Parent();
// ^^^^^^^^^^^^^


Child.prototype.incJ = function () { this.j++; };
Child.prototype.toString = function() {
return this.parentToString() + " and child[" + this.j + "]";
};

var p = new Parent(42);


var c = new Child(37,87);
alert(p.toString()); // parent[42]
alert(c.toString()); // parent[37] and child[87]
p.incI();
alert(p.toString()); // parent[43]
alert(c.toString()); // parent[37] and child[87]
c.incI();
alert(p.toString()); // parent[43]
alert(c.toString()); // parent[38] and child[87]
c.incJ();
alert(c.toString()); // parent[38] and child[88]
alert(p.incJ); // undefined

in my Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040709
Firefox/0.9.0+.

BTW, Function.prototype.call() can AFAIS be implemented as follows:

// types.js stripped down to the absolute necessary
function Types() {}
var types = new Types();
Types.prototype.OVERWRITE = 1; // Overwrite existing properties

/**
* Adds/replaces prototype properties of an object.
*
* @argument object o
* Object specifying the properties to be added/replaced.
* The name of each property serves as the name for the
* prototype property, its value as value as the value
* of that property.
* @argument number iFlags
* Flags for the modification.
*/
Function.prototype.addToPrototype =
function function_addToPrototype(o, iFlags)
{
for (var i in o)
{
if (typeof this.prototype[i] == "undefined"
|| typeof iFlags == "undefined"
|| (iFlags & types.OVERWRITE))
{
this.prototype[i] = o[i];
}
}
}

if (isMethodType(typeof eval))
{
Function.addToPrototype(
{apply: /**
* Applies a method of another object in the context
* of a different object (the calling object).
*
* @prototype method
* @argument object thisArg
* Reference to the calling object.
* @argument Array argArray
* Arguments for the object.
*/
function function_apply(thisArg, argArray)
{
var a = new Array();
for (var i = 0, len = argArray.length; i < len; i++)
{
a[i] = argArray[i];
}

eval("thisArg(" + a.join(", ") + ")");
},
call: /**
* Calls (executes) a method of another object in the
* context of a different object (the calling object).
*
* @argument object thisArg
* Reference to the calling object.
* @arguments _ _
* Arguments for the object.
*/
function function_call(thisArg)
{
var a = new Array();
for (var i = 1, len = arguments.length; i < len; i++)
{
a[i] = arguments[i];
}

eval("thisArg.this(" + a.join(", ") + ")");
}
});
}

(CMIIW)


PointedEars

Lasse Reichstein Nielsen

unread,
Jul 12, 2004, 7:47:44 AM7/12/04
to
Thomas 'PointedEars' Lahn <Point...@nurfuerspam.de> writes:

> Can you provide a reasonable explanation and/or an example which
> proves that the inheritObject() method is needed? AFAIS it is
> not,
>
> function Child() {
> Parent.call(this);
> // child initalization;
> }
> Child.prototype = new Parent();
>
> would suffice.

It works almost the same, except that the prototype is now an
initialized object. It will rarely matter, since the initialization is
repeated by the Parent.call(this) call. However, if the Parent
function takes arguments, then it is not obvious which to use for the
prototype instance, and you could potentially have an initialization
that overwrites different properties of the prototype depending on
how it's called.
---
function Complex(x, y, polar) {
if (!polar) {
this.x = x;
this.y = y;
} else {
this.mag = Math.sqrt(x*x+y*y);
var ang = this.mag > 0 ? Math.acos(Math.abs(x/this.mag)) : 0;
if (x < 0) { ang = Math.PI - ang; }
if (y < 0) { ang += Math.PI; }
this.ang = ang;
this.toString = function() {
return x+"+"+y+"i";
}
}
}
Complex.prototype.toString = function() {return this.x+"+"+this.y+"i"; }
---

Then it would be wrong to make a subclass like this:
---
function Sub(x, y, polar) {
Complex.call(this,x,y,polar);
//...
}
Sub.prototype = new Complex(0,0,true);
---

(Obviously, I could initialize the prototype with (0,0,false) in this
example, but it's an example of what can go wrong).

It's purely defensive programming to use the inheritObject function.
By not executing any unnecessary code, the lieklyhood of an
incompatability, which will probably be hard to find, is minimized.

> BTW, Function.prototype.call() can AFAIS be implemented as follows:

...
> call: /**
...


> function function_call(thisArg)
> {
> var a = new Array();
> for (var i = 1, len = arguments.length; i < len; i++)
> {
> a[i] = arguments[i];
> }
>
> eval("thisArg.this(" + a.join(", ") + ")");

Is "thisArg.this" even syntactically correct? It seems to use
"this" as the name of a property, and "this" is a reserved word.
I assume this is what should call the function as a method
of thisArg.

Using "eval" seems to be the only way to implement a call with a
variable number of arguments (without using apply), but this way of
doing it is not sufficient.

The problem occurs if an argument doesn't convert to a string that is
a language literal for itself. Only numbers and booleans converts to
literals of themselves. If you pass the string "true" to this function,
then the argument to eval will contain the unquoted string "true", e.g.
function_call("true")
will eventually evaluate the string:
thisArg.this(true)
which is not the same call.

You can "stringify" strings, Array's, Object's and RegExp's using
literal notation, but it will fail to preserve the identity of the
objects.

For other objects, either created using your own constructors or using
build in types like Date, there is no literal notation. You might be
able to create a new object with a new constructor call with appropriate
arguments, but again it fails to preserve object identity.

You will probably also want to return the return value of the function
call.


A better approach is *not* to embed the values in the string to be
evaluated, but just embed references to local variables containing the
values. Those you have complete control over:
---
/**
* Finds a name that the given object doesn't have a property
* of that name.
*
* @param object Object to find property for.
*/
function findNonExistingPropertyName(object) {
var prop = "x"; // would start at "" if all browsers were bug free
while (typeof(object[prop]) != "undefined") {
prop += "x";
}
return prop;
}

/**
* Calls function (this) as a method of the give object with
* the provided parameters
*
* @param object The object to use as "this" for the function call.
* @param ... arguments to the function.
*/
function functionCall(object /*, ... */) {
var args = new Array();
var argNames = new Array();
for(var i=1;i<arguments.length;i++) {
args[i] = arguments[i];
argNames[i-1] = "args["+i+"]";
}
var nonEPN = findNonExistingPropertyName(object);
object[nonEPN] = this;
var val = eval("object[\""+nonEPN+"\"]("+
argNames.join(",")+")");
delete object[nonEPN];
return val;
}
---

An example to show that it works:
---
Function.prototype.myCall = functionCall;
var o = { x:42 };
function f(y) {
this.y = y;
return this.x;
}
var oarg = { toString : function() { return "THIS WORKED"; } };
var res = f.myCall(o, oarg);
alert([res, o.y, o.y == oarg]); // [42,THIS WORKED,true]
---

John G Harris

unread,
Jul 12, 2004, 4:22:23 PM7/12/04
to
In article <40f25272$0$6968$e4fe...@news.xs4all.nl>, Vincent van
Beveren <vin...@provident.remove.this.nl> writes

<snip>


>I just
>would like to create a one-on-one parent to child relationship. With
>prototypeing it seems that I can only assign one parent to a group of
>child objects. But that means that all childs have the same instance of
>a parent.
>
>The problem is that I have an object and I want to create a new one
>extending the capabilities of the current object. However, each
>instance of the extended object, needs to have it own instance of
>the parent object.

<snip>

My example gave you this kind of structure. Isn't this what you are
asking for?

============
| Parent | Parent's prototype object
| methods |
============
|
|
============
| Child | Child's prototype object
| methods |
============
|
| prototype chain,
| shared by all Child instances
Child instance |
============ |
| Parent |-----
| data |
|----------|
| Child |
| data |
============

Javascript gives you several other ways to do almost the same job, which
must be confusing for newcomers :-(

John
--
John Harris

Vincent van Beveren

unread,
Jul 14, 2004, 3:27:42 AM7/14/04
to
Hey John,

> My example gave you this kind of structure. Isn't this what you are
> asking for?

Yes, it does give that, but the problem is that the parent object
already exists, Modifying it to work like your example is just a lot of
work.

> Javascript gives you several other ways to do almost the same job,
> which must be confusing for newcomers :-(

Well, I've been working with JavaScript for 6 years now, I just never
really did much with inheritance. It does confuse me though.

Thanks for all the info,
Vincent


0 new messages