Jun wrote:
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[i] + "\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...