Constructor is never called

Discussion in 'Javascript' started by Jun, Nov 9, 2003.

  1. Jun

    Jun Guest

    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
    Jun, Nov 9, 2003
    #1
    1. Advertising

  2. "Jun" <> schreef in bericht
    news:...
    >
    > 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
    Janwillem Borleffs, Nov 9, 2003
    #2
    1. Advertising

  3. (Jun) writes:

    > <script>


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

    <script type="text/javascript">

    > 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
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Nov 9, 2003
    #3
  4. Jun

    Fox Guest

    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 + "\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...
    Fox, Nov 10, 2003
    #4
  5. Fox <> writes:

    > Jun wrote:


    > > 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);
    > }
    > }


    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.

    > >
    > > //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".


    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.

    > > //"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).


    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
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Nov 10, 2003
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ryan Park
    Replies:
    2
    Views:
    671
    Joerg Jooss
    Jan 3, 2005
  2. Soren Kuula
    Replies:
    1
    Views:
    440
    Henry S. Thompson
    Dec 1, 2005
  3. Replies:
    6
    Views:
    347
    Howard
    Mar 18, 2005
  4. Kevin
    Replies:
    4
    Views:
    412
    Irrwahn Grausewitz
    Oct 17, 2003
  5. Generic Usenet Account
    Replies:
    10
    Views:
    2,202
Loading...

Share This Page