Prototyping - explanation required

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Will

    Prototyping - explanation required

    function obj1() {
    this.children;

    this.Children = function() {
    if(typeof(this. children) === 'undefined') {
    this.children = new col();
    }
    return this.children;
    }

    this.Children() .Add(1);
    }

    obj2.prototype = new obj1();
    function obj2() {
    obj1.call(this) ;
    this.Children() .Add(1);
    }

    obj3.prototype = new obj2();
    function obj3() {
    obj2.call(this) ;
    this.Children() .Add(1);
    }

    function col() {
    var arr = new Array();

    this.Add = function(item) {
    arr[arr.length] = item;
    }

    this.Count = function(item) {
    return arr.length;
    }
    }

    var a = new obj3();
    alert(a.Childre n().Count());

    I have been learning how to use prototyping with private static
    members and today noticed something new to me. In the above example, 6
    is returned when 3 would be desirable.

    Turning the public member "this.child ren" into a private member (e.g.
    "var children") corrects the issue, as does removing the lines
    "obj1.call(this )" and "obj2.call(this )".

    Am I correct in deducing that any public members in a prototyped
    object will be re-evaluated for each derived object? So I'm guessing
    that in this case, when obj3 is instantiated:

    1) obj1, obj2 and obj3 all call children.Add() in the constructor
    (Count = 3)
    2) obj1.call(this) causes obj1 to call children.Add() again
    3) obj2.call(this) causes obj2 to call children.Add() again, and also
    causes a repeat of (2).

    As a result children.Add() is called 6 times instead of 3.

    Can anyone explain the above behaviour or correct my interpretation? I
    am curious to know what xactly is happening and how to work around it.

    Thanks

    Will
  • Lasse Reichstein Nielsen

    #2
    Re: Prototyping - explanation required

    mrbrown_1998@ya hoo.com (Will) writes:
    [color=blue]
    > function obj1() {
    > this.children;[/color]

    This line does nothing (except perhaps evaluating to undefined).
    I assume it was originally a "var children" line :)
    [color=blue]
    > this.Children = function() {
    > if(typeof(this. children) === 'undefined') {[/color]

    (you only need == for string comparison. If you wrote
    if(this.childre n === undefined)
    i.e., compare to the value itself, not a string, then the === is
    needed. Still, better safe than sorry :)
    [color=blue]
    > this.children = new col();
    > }
    > return this.children;
    > }
    >
    > this.Children() .Add(1);
    > }[/color]
    [color=blue]
    > obj2.prototype = new obj1();
    > function obj2() {[/color]

    I find it slightly confuzing to set a property of something that is
    not declared until the next line. I know ECMAScript declares all functions
    before executing any code, but it is still ... unsetteling.
    [color=blue]
    > obj1.call(this) ;
    > this.Children() .Add(1);
    > }[/color]


    [color=blue]
    > obj3.prototype = new obj2();
    > function obj3() {
    > obj2.call(this) ;
    > this.Children() .Add(1);
    > }
    >
    > function col() {
    > var arr = new Array();
    >
    > this.Add = function(item) {
    > arr[arr.length] = item;
    > }
    >
    > this.Count = function(item) {
    > return arr.length;
    > }
    > }
    >
    > var a = new obj3();
    > alert(a.Childre n().Count());
    >
    > I have been learning how to use prototyping with private static
    > members and today noticed something new to me. In the above example, 6
    > is returned when 3 would be desirable.[/color]
    [color=blue]
    > Turning the public member "this.child ren" into a private member (e.g.
    > "var children") corrects the issue, as does removing the lines
    > "obj1.call(this )" and "obj2.call(this )".[/color]

    Yes. If you change children to a local variable of the obj1 function,
    then the two later calls of obj1 will create Children functions that
    operate on the new variable. So each new obj2 object will get its own
    Children function and children variable.

    If this.children is a property, the new Children function assigned
    to obj2 objects will all refer to the same property of the obj1 object
    that is obj2's prototype. Only one of them will find it undefined.

    Removing the calls to obj1 and obj2 should lower the count, since they
    perform three of the Add(1)'s.
    [color=blue]
    > Am I correct in deducing that any public members in a prototyped
    > object will be re-evaluated for each derived object?[/color]

    I am not sure exactly what you mean, but I think the answer is no.
    Members (i.e., properties of objects) are not evaluated at all, they
    just sit there until you change them.
    [color=blue]
    > So I'm guessing that in this case, when obj3 is instantiated:
    >
    > 1) obj1, obj2 and obj3 all call children.Add() in the constructor
    > (Count = 3)
    > 2) obj1.call(this) causes obj1 to call children.Add() again
    > 3) obj2.call(this) causes obj2 to call children.Add() again, and also
    > causes a repeat of (2).[/color]

    Let me try to figure out what happens. Then we can compare :)
    (And after doing that, yes, I agree. Derivation follows:)

    Some functions are defined. Then the following lines are executed:

    obj2.prototype = new obj1();
    This instantiates obj1instance.ch ildren and adds 1 to it.
    State after this:
    [obj2]--prototype-->[obj1ins:col(Cou nt=1)]
    (i.e., the obj2 function has a property called "prototype" that points
    to an instans of obj1 with a collection with Count()==1)

    obj3.prototype = new obj2();
    This creates obj3 and an obj2 instance:
    [obj3]--prototype-->[obj2ins]--<<proto>>-->[obj1ins:col(Cou nt=1)]
    This also executes the obj2 function:
    obj1.call(this) ;
    It creates a new this.Children function, but not a new children collection.
    It then adds one to the collection.
    this.Children() .Add(1);
    It adds another one.
    State:
    [obj3]--prototype-->[obj2ins]--<<proto>>-->[obj1ins:col(Cou nt=3)]
    Then we execute:
    var a = new obj3();
    This creates a new obj3 instance:
    a = [obj3ins]--<<proto>>-->[obj2ins]--<<proto>>-->[obj1ins:col(Cou nt=3)]
    and executes the obj3 function:
    obj2.call(this) ;
    this.Children() .Add(1);
    The first call executes obj2:
    obj1.call(this) ;
    this.Children() .Add(1);
    The first call again executes obj1, which creates a new Children function
    and does:
    this.Children() .Add(1);
    That is, a total of three calls to Add(1), bringin us to a count of 6.


    In short, if we show the unfolded function calls indented, the
    code that is executed is:

    obj2.prototype = new obj1();
    this.children = new col();
    this.Children() .Add(1);
    obj3.prototype = new obj2();
    obj1.call(this) ;
    this.Children() .Add(1);
    this.Children() .Add(1);
    a = new obj3();
    obj2.call(this) ;
    obj1.call(this) ;
    this.Children() .Add(1);
    this.Children() .Add(1);
    this.Children.A dd(1);
    [color=blue]
    > As a result children.Add() is called 6 times instead of 3.[/color]

    I can't see why it should only be 3. You explicitly call functions
    that Add(1). Nothing automatic is happening.
    [color=blue]
    > Can anyone explain the above behaviour or correct my interpretation? I
    > am curious to know what xactly is happening and how to work around it.[/color]

    I hope this is readable. :)

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

    Comment

    Working...