Constructor is never called

J

Jun

I have following script

<script>
var Animal = function(name){
this.name = name;
}


Animal.prototype.eat = function (food)
{
alert(this.name + " eat " + food);
}

//constructor for Dog
var Dog = function(){
}

//"inheriting" from Animal
Dog.prototype = new Animal();
Dog.prototype.constructor = Animal;

var myDog = new Dog("ddd");

myDog.eat("bone");

</script>

The result was that Dog's constructor was called but Animal's constructor
was never called so I got "undefined eat bone".

Is the javascript inheritant doesn't support calling super constructor or
I didn't use "Dog.prototype.constructor" correctly?

thanks
 
J

Janwillem Borleffs

Jun said:
The result was that Dog's constructor was called but Animal's constructor
was never called so I got "undefined eat bone".

Is the javascript inheritant doesn't support calling super constructor or
I didn't use "Dog.prototype.constructor" correctly?

Actually, it is called. But since you are not passing it an argument and the
Dog constructor doesn't set the name property, it remains undefined.

To fix this, you could either pass the argument to the Dog constructor:

//constructor for Dog
var Dog = function(name) {
this.name = name;
}

or pass it when initiating the prototype property:
Dog.prototype = new Animal("ddd");

Anither option is to define a setter method in the Animal constructor
function:

var Animal = function() {
this.setName = function (name) {
this.name = name;
};
}

This can then be called seperatly to set the dog's name:
.....
var myDog = new Dog();
myDog.setName("goofy");

myDog.eat("bone");
.....

JW
 
L

Lasse Reichstein Nielsen


For pedantic reasons, I'll remind you (and everybody else :) that the
type attribute is required in HTML 4 and later.

var Animal = function(name){
this.name = name;
}
Animal.prototype.eat = function (food)
{
alert(this.name + " eat " + food);
}

//constructor for Dog
var Dog = function(){

As Janwillem Borleffs said, you don't set the name.
Javascript doesn't call the superclass' constructor, mostly because
there are no classes in Javascript at all, so no superclasses either.
If you want to call the superclass' constructor, you have to do
it manually:
Animal.call(this,arguments[0]);
or just (since you set it up with "Dog.prototype.constructor = Animal;")
this.constructor(arguments[0]);
(you might want to make Dog take an argument :)
}

//"inheriting" from Animal

Don't say "inheriting". It isn't. Javascript is prototype based, not
class based, so there is no real inheriting.
Dog.prototype = new Animal();

This means that a new Dog object will have a [[prototype]] reference
to an Animal object with an undefined name (you call Animal with
no argument, so the name gets set to undefined)>
Dog.prototype.constructor = Animal;

The prototype's constructor is never called automatically. If you
want to call it, you must do it yourself.
The result was that Dog's constructor was called but Animal's constructor
was never called so I got "undefined eat bone".

You called it yourself in
"dog.prototype = new Animal();"
It is never called automatically.
Is the javascript inheritant doesn't support calling super constructor or
I didn't use "Dog.prototype.constructor" correctly?

There is no inheritance. You didn't say what you expected
Dog.prototype.constructor to do, but it probably doesn't do what you
expect. (When asking for help, always say both what actually happenes
and what you expected to happen).

/L
 
F

Fox

Jun said:
I have following script

<script>
var Animal = function(name){
this.name = name;
}

Animal.prototype.eat = function (food)
{
alert(this.name + " eat " + food);
}

If you *know* you're going to include this method -- just declare it
within the object definition:

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

this.eat = function(food)
{
alert(this.name + " eats " + food);
}
}


Use prototype for predefined objects like Array, Number, String, etc...
or declaring superclasses...
//constructor for Dog
var Dog = function(){
}

This is not an object (much less a constructor) -- it's an empty
function... in order to be considered an object, it *requires* at least
one property or method utilizing the keyword "this".
//"inheriting" from Animal
Dog.prototype = new Animal();
Dog.prototype.constructor = Animal;

Not required and not recommended -- the constructor is automatically
Animal (or whatever topmost level object is utilized).
var myDog = new Dog("ddd");

myDog.eat("bone");

</script>

The result was that Dog's constructor was called but Animal's constructor
was never called so I got "undefined eat bone".

Is the javascript inheritant doesn't support calling super constructor or
I didn't use "Dog.prototype.constructor" correctly?
answered...


thanks

The "super" constructor IS automatically called as soon as it is
prototyped from the "subclass" [or, probably, more technically, as soon
as the object prototyped is parsed since you can prototype the
superclass prior to defining it] -- it becomes, essentially, the *only*
constructor used for the object.

Dog's constructor (if Dog is actually an Object) is not Dog, it's
Animal, as you will see from the alerts:


function
Animal(args)
{


this.genus = args;

alert("constructor called -- animal genus = " + this.genus);
// fires when called...

// use a JS superclass as repository
// for common properties or methods

this.getType = function()
{
alert (this.type); // declared in Dog
}
this.getBreed = function()
{
alert (this.breed); // declared in Cat
}

}

function
Dog(arg)
{
alert(this.constructor); // shows function Animal
this.type = arg;

}

function
Cat(arg)
{
alert(this.constructor); // shows function Animal
this.breed = arg; // different than Dog...
}

// the point of subclassing is to have different sets of properties and methods
// particular to that class -- the super providing all of the common properties
// and methods...

Dog.prototype = new Animal("canis"); // args common to ALL Dog objects
Cat.prototype = new Animal("felis"); // args common to ALL Cat objects

// note -- do not use Cat/Dog.prototype.constructor
// the constructor is automatically set by JS and
// in this case, the constructor => "Animal" [the entire function
declaration]
// It is at this point that the "superclass" constructor is "fired"
// you get the "constructor called..." alert -- 2 in a row


var d = new Dog("doberman");
var c = new Cat("siamese");

// these fire the constructor Animal alerts and set their respective
"local" properties
// as per the instructions within these object declarations


// use subclass reference to access superclass/inherited methods/properties:
d.getType();
d.getBreed(); // shows "undefined"


c.getType(); // shows undefined
c.getBreed();

alert(d.genus + "\n" + c.genus); // shows "superclass" property of instance



Taking this even further, you have the case of extending the subclass
with yet another subclass:

function
dogFood(brand)
{
alert(this.constructor); // again -- will show Animal!
this.brand = brand;
}

dogFood.prototype = new Dog("all breeds"); // notice -- NOT Animal here


Even though Dog is used as the prototype declaration, you will see that
Animal is actually the constructor called [since it is the constructor
for Dog and Cat] -- "all breeds" is loaded into the Dog instance's type
property as default and:

var df = new dogFood("purina");

will load "purina" into the brand property.

df.genus will show "canis" and calling df.getType() will fire the alert
showing "all breeds" as the type.


Now, for fun, put:

function
Lifeform(kind)
{

this.lifeform = kind;

this.showAll = function()
{
var s = "";
for(var i in this)
{
s += i + ": " + this + "\n";
}

alert(s);
}
}

Animal.prototype = Lifeform("fur-bearin' critter");
// can be declared BEFORE Animal is actually declared

at the head of everything above...

and

d.showAll(); // called from Dog instance
and
df.showAll(); // called from dogFood instance

to observe the differences between object instances... what you end up
with is a large object with everything included -- essentially something like:

var dog = new (Dog + Animal + Lifeform); // very pseudocode...
// no such thing in JS
var cat = new (Cat + Animal + Lifeform);

var dogfood = new (dogFood + Dog + Animal + Lifeform);


You can change the "default" values passed to "superclasses" anytime you
wish by redeclaring the prototype:

dogFood.prototype = new Dog("my pet"); // changed from "all breeds"


var dogfood2 = new dogFood("iams");

Now compare df.showAll() and dogfood2.showAll() -- you'll see that
df.type still shows "all breeds" and "purina" while dogfood2.type
(default) has changed to "my pet" and brand to "iams". The new
prototype takes effect for all subsequent instantiations of class
dogFood (until explicitly changed). In other words, changing the
prototype does not change already existant instances of the object...
[you are not limited to redeclaring the prototype of the extended class
-- you could as easily redefine prototype new Animal("new default") or
Lifeform (etc) from any point in the "chain" of inheriting objects. This
gives JS a level of flexibility beyond that available from more
conventional class oriented objects where these kinds of "on-the-fly"
changes are not available.

Nowhere did I use .call() -- nowhere did I use .constructor... Objects
in JS are not that complicated. Logic dictates that there is inheritance
since methods and/or properties do not need to be redeclared in each
"class" declaration or overridden (although that is your option if you
so choose.) Although JS has a different object model than other
programming languages like Java, the *language* that we have to describe
object models in general is limited to a similar set of terms that are
used to describe both prototype based objects as well as class based
objects...so, superclass/subclass and inheritance are used to describe
similar *functionalities* in both even though there are syntactical
differences [there is, technically, no class declarator in JS; however,
there is likewise no terminology for superobject/subobject, super/sub
prototype, or super/sub function either]. Check out Netscape's
JavaScript User's Guide for an excellent description (and examples) of
the differences between prototype-based and class-based object oriented languages.


Hope this helps...
 
L

Lasse Reichstein Nielsen

Fox said:
Jun wrote:

If you *know* you're going to include this method -- just declare it
within the object definition:

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

this.eat = function(food)
{
alert(this.name + " eats " + food);
}
}

No. Adding the function to the prototype is better, because it only
creates one function, not one function per object.
Use prototype for predefined objects like Array, Number, String, etc...
or declaring superclasses...

What he does, is perfectly good use of the prototype object.
This is not an object (much less a constructor) -- it's an empty
function... in order to be considered an object, it *requires* at least
one property or method utilizing the keyword "this".

It is actually an object (all functions are). It is also a perfectly good
constructor. It doesn't require anything, it is the minimal function and
the minimal constructor.
Not required and not recommended -- the constructor is automatically
Animal (or whatever topmost level object is utilized).

Correct. The constructor property of Animal.prototype is automatically
Animal. When you assign a new Animal() to Dog.prototype, that means
that Dog.prototype.constructor is already Animal.
var myDog = new Dog("ddd");

myDog.eat("bone");

</script>

The result was that Dog's constructor was called but Animal's constructor
was never called so I got "undefined eat bone".

Is the javascript inheritant doesn't support calling super constructor or
I didn't use "Dog.prototype.constructor" correctly?
answered...


thanks

The "super" constructor IS automatically called as soon as it is
prototyped from the "subclass" [or, probably, more technically, as soon
as the object prototyped is parsed since you can prototype the
superclass prior to defining it] -- it becomes, essentially, the *only*
constructor used for the object.

I don't understand this.

Are you saying that the Animal constructor is called when the
prototype property of Dog is assigned?

How do you prototype a "class" before defining it?
Dog's constructor (if Dog is actually an Object) is not Dog, it's
Animal, as you will see from the alerts:

Technically, the Dog function is the constructor of Dog elements. The
created elements' "constructor" property is the Animal function,
though, but you can't trust that property since you can, and do,
override it. It is purely descriptive, and is never called by
Javascript itself. If you never refer to the constructor property,
it doesn't matter what value it has.

What you can trust is the "instanceof" operator.
---
Animal.prototype.constructor = 42;
var d = new Dog();
alert(d instanceof Dog);
alert(d instanceof Animal);
---
alerts true twice.

Changing the constructor property makes no difference for "instanceof".

---
function Foo(){}
function Bar(){}
Bar.prototype.constructor = Foo;
function Baz(){};
Baz.prototype = new Bar();
var baz = new Baz();
alert([baz.constructor,baz instanceof Foo]);
---

[snip perfectly good functions]
dogFood.prototype = new Dog("all breeds"); // notice -- NOT Animal here

Yikes, dogFood is a Dog. Cannibalism! :)
Even though Dog is used as the prototype declaration, you will see that
Animal is actually the constructor called [since it is the constructor
for Dog and Cat]

No it isn't. The Animal function is only called twice (as witnessed by
the alerts), and that is in these lines:
Dog.prototype = new Animal("canis"); // args common to ALL Dog objects
Cat.prototype = new Animal("felis"); // args common to ALL Cat objects

It is not called again for dogFood. The same Animal object that is the
prototype object of Dog, is also an object in the prototype chain of
dogFood (or are we reading "called" differently?)

Otherwise I agree.
Animal.prototype = Lifeform("fur-bearin' critter");
// can be declared BEFORE Animal is actually declared

Only apparently so, but function declarations are execucted before the
remaining code, no matter where they are in the code (even after a
return). So, the function Animal is declared before the prototype
is added to it, it is just placed later in the syntax.

That is only true for function declarations. Compare these two:
---
Foo.prototype.bar = 42;
function Foo(){};
alert(new Foo().bar);
---
and
---
Foo.prototype.bar = 42;
var Foo = function (){};
alert(new Foo().bar);
---
The latter fails because at the first line, Foo doesn't refer to an
object with a "prototype" property.
You can change the "default" values passed to "superclasses" anytime you
wish by redeclaring the prototype:

dogFood.prototype = new Dog("my pet"); // changed from "all breeds"


var dogfood2 = new dogFood("iams");
[you are not limited to redeclaring the prototype of the extended class
-- you could as easily redefine prototype new Animal("new default") or
Lifeform (etc) from any point in the "chain" of inheriting objects. This
gives JS a level of flexibility beyond that available from more
conventional class oriented objects where these kinds of "on-the-fly"
changes are not available.

You still have to upgrade the prototypes of the rest of the chain.

If you changed Animal's prototype:

Animal.prototype = new Lifeform("small and furry")
and then created a new Dogfood
var dogfood3 = new dogFood("Whiskas for dogs");
this object would still refer to the old animal prototype, because
its prototype object was created before the change.
To make the dogfood3 use the new Animal prototype, you need to
update Dog and dogFood too:
Dog.prototype = new Animal("canis");
dogFood.prototype = new Dog("all breeds");
Although JS has a different object model than other programming
languages like Java,

Yes, it is much closer to Smalltalk or Self, both prototype based
object oriented languages. Only with a comforting C-like syntax :)
Check out Netscape's JavaScript User's Guide for an excellent
description (and examples) of the differences between
prototype-based and class-based object oriented languages.

Are you referring to this
<URL:http://devedge.netscape.com/library/manuals/2000/javascript/1.5/guide/obj2.html#1013803>
?

/L
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top