Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 13 of 13
  1. #1
    New to the CF scene
    Join Date
    Dec 2012
    Posts
    3
    Thanks
    1
    Thanked 0 Times in 0 Posts

    prototype question

    Hi My name is Robin, I'm new at this forum and I am practicing javascript oop.
    I'm getting stuck when it comes to prototype. I've read a lot about it but it is very hard to understand what prototype does.
    I've made a little code from codeacedamy to explain my question.


    function Cat(name, breed) {
    this.name = name;
    this.breed = breed;
    // this.meow = function(){
    // console.log("meoww!");
    // };
    }

    // let's make some cats!
    var cheshire = new Cat("Cheshire Cat", "British Shorthair");
    var gary = new Cat("Gary", "Domestic Shorthair");

    //Cat.prototype.meow = function(){
    // console.log("meoww!");
    //};

    // add code here to make the cats meow!
    cheshire.meow();
    gary.meow();


    My question: What is the difference between the two parts I placed in comments. I can let the cat "meoww!" just by giving the constructor this function, but I should do it on the prototype way. But I have no idea what the difference is.
    I hope anyone can help my.

    I'm sorry for my bad english.

    Gr Robin
    Last edited by robin193; 12-23-2012 at 10:50 PM.

  • #2
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    The following creates a separate meow method for each and every object that you create from Cat. So if you define 100 cats then you will have 100 copies of the method.

    Code:
    this.meow = function(){
    console.log("meoww!"); 
    };
    The following will create ONE copy of the meow method to share between all objects created from Cat - so that if you create 1000 cats you will still have only one copy of the method that is shared between all of them.

    Code:
    Cat.prototype.meow = function(){
    console.log("meoww!");
    };
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • Users who have thanked felgall for this post:

    robin193 (12-24-2012)

  • #3
    New to the CF scene
    Join Date
    Dec 2012
    Posts
    3
    Thanks
    1
    Thanked 0 Times in 0 Posts
    thanks for the fast reply,
    so if I understand you correctly, on the prototype way the program is faster because the program has to execute the method once.

  • #4
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,148
    Thanks
    39
    Thanked 506 Times in 500 Posts

    Arrow

    Quote Originally Posted by robin193 View Post
    thanks for the fast reply,
    so if I understand you correctly, on the prototype way the program is faster because the program has to execute the method once.
    I don't believe he said faster. The function will probably execute at a similar speed each time it is called.

    What would be gained is the memory necessary for 99 extra versions of the method that performs the same task.

  • #5
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,700
    Thanks
    80
    Thanked 4,657 Times in 4,619 Posts
    I would like to point out that you don't *HAVE* to use prototype to achieve the same memory savings.

    You *can* code it as:
    Code:
    function Cat(name, breed) {
        this.name = name;
        this.breed = breed;
        this.meow = Meow;
    };
    
    function Meow()
    {
        console.log("meoww!"); 
    };
    The advantage of using Cat.protoype.meow is that the function will be only available to Cat instances. In the code here, the Meow function could, for example, be called without reference to a Cat instance.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #6
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    Quote Originally Posted by Old Pedant View Post
    ...
    The advantage of using Cat.protoype.meow is that the function will be only available to Cat instances. In the code here, the Meow function could, for example, be called without reference to a Cat instance.
    you can call prototype methods in the exact way: by name. It will NOT be
    "only available to" anything. a name is a name, and call/apply/bind work on object paths the same as lexical entities.

    [QUOTE=felgall;1301849]The following creates a separate meow method for each and every object that you create from Cat. So if you define 100 cats then you will have 100 copies of the method.

    Code:
    this.meow = function(){
    console.log("meoww!"); 
    };
    that's not what the ecmaScript 3 spec says, i'll have to check 5. Functions are objects. Objects are passed byRef. this is determined at execution time. It's not safe to say that 100 distinct yet identical mallocs will result from the method...



    Quote Originally Posted by jmrker View Post
    What would be gained is the memory necessary for 99 extra versions of the method that performs the same task.

    i don't see the memory savings, can you clarify what you mean?
    Last edited by rnd me; 12-25-2012 at 06:29 AM.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #7
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,700
    Thanks
    80
    Thanked 4,657 Times in 4,619 Posts
    Quote Originally Posted by rnd me View Post
    you can call prototype methods in the exact way: by name. It will NOT be
    "only available to" anything. a name is a name, and call/apply/bind work on object paths the same as lexical entities.
    Technically correct.

    But look at the mess it takes to invoke a function defined via prototype in any other way.
    Code:
    function Cat( name, breed )
    {
        this.name = name;
        this.breed = breed;
    }
    Cat.prototype.meow = function() { alert( this.name + " says meow" ); };
    
    var f = new Cat( "Fred", "xx" );
    f.meow();
    
    var g = {
        name : "George",
        breed : "Manx"
    };
    
    Cat.prototype.meow.bind( g )( ); // ugly, isn't it?
    ************************

    i don't see the memory savings, can you clarify what you mean?
    He was assuming the Felgall was correct about the extra 99 copies, of course.

    You may well be correct that this doesn't occur. But I wouldn't be willing to bet that is true in, for example, MSIE 7 (to pick the obvious example).
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #8
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by rnd me View Post
    Functions are objects. Objects are passed byRef. this is determined at execution time. It's not safe to say that 100 distinct yet identical mallocs will result from the method...
    You overlooked the fact that new is being used to make the copies.

    A simple way to prove that separate copies of the method exist for each object after creating them using 'new' would be to update the code in the original method. You will soon see that it does not update the copies of that method that have already been made using 'new'.

    It is only when you don't use 'new' that objects are passed by reference.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #9
    Senior Coder Logic Ali's Avatar
    Join Date
    Sep 2010
    Location
    London
    Posts
    1,028
    Thanks
    0
    Thanked 207 Times in 202 Posts
    Quote Originally Posted by felgall View Post

    A simple way to prove that separate copies of the method exist for each object after creating them using 'new' would be to update the code in the original method. You will soon see that it does not update the copies of that method that have already been made using 'new'.
    Code:
    obj = function()
    {
      this.func = function()
      {
       
      } 
    }
    
    alert( new obj().func === new obj().func ); // false
    
    
    objP = function()
    {
     
    }
    
    objP.prototype.func = function()
    {
       
    }
    
    alert( new objP().func === new objP().func ); // true

  • #10
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    Quote Originally Posted by felgall View Post
    A simple way to prove that separate copies of the method exist for each object after creating them using 'new' would be to update the code in the original method. You will soon see that it does not update the copies of that method that have already been made using 'new'.
    the use of "new" has nothing to do with it. The JS engine generates internal function objects, and those objects get re-used. If two functions, even enclosed/anon functions, are the same code, the engine is allowed to substitute a pointer instead of a duplicate.




    a simple test and chrome's task manager can shed some light on this:

    in two different tabs, run the code below, and keep the focus off both tabs for at least 90 secs after execution to allow them to stabilize.

    inlined
    Code:
    function Cat( name, breed ){
        this.name = name;
        this.breed = breed;
      this.meow = function() { alert( this.name + " says meow" ); };
    }
    
    var r=[];
    for(var i=0, mx=999999;i<mx;i++){
     r.push(new Cat("kitty", "persian"))
    }
    
    setTimeout(function(){ document.title='inlined'; }, 2000 );

    proto'd
    Code:
    function Cat( name, breed ){
        this.name = name;
        this.breed = breed;
    }
    Cat.prototype.meow = function() { alert( this.name + " says meow" ); };
    
    var r=[];
    for(var i=0, mx=999999;i<mx;i++){
     r.push(new Cat("kitty", "persian"))
    }
    
    
    setTimeout(function(){ document.title='protod'; }, 2000 );



    results
    since there were 1 million copies stored, fresh copies of the function object would have to cram into 238k or ~250,000bytes, 1/4 of a byte per method.

    even on the total ram footprint, I only saw one byte more per object on the inline version:

    Code:
    tab	jsmem	js live
    inline	7,060k	1,762k
    proto  	6,080k	1,524k

    one possibility that's compatible with the observation is that V8 uses an 8 bit pointer when the symbol count is low. that's just a guess, i'm not versed on implementation optimizations. either way, the results support what i've been saying all along: yes, in-lining might use a little more ram, but it won't use a linear scaling amount either.


    If don't take my word, or the test's word for it, take the spec's!

    from ECMAScript Language Specification Edition 3 (24-Mar-00) section 13.1.2 - Joined Objects
    Joined objects are used as a tool for precise specification technique in this standard. They are not meant to be used as a
    guideline to how Function objects are implemented in practice. Rather, in practice an implementation may detect when the
    differences in the [[Scope]] properties of two or more joined Function objects are not externally observable and in those cases
    reuse the same Function object rather than making a set of joined Function objects. This is a legal optimisation because this
    standard only specifies observable behaviour of ECMAScript programs.
    Furthermore, section 13.2 explicitly mentions the exact case we've been discussing (in rather simple language) :
    Step 1 allows an implementation to optimise the common case of a function A that has a nested function B where B is not
    dependent on A. In this case the implementation is allowed to reuse the same object for B instead of creating a new one every
    time A is called. Step 13 makes this optimisation optional; an implementation that chooses not to implement it will go to step 2.
    Last edited by rnd me; 12-26-2012 at 10:08 AM.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #11
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    Quote Originally Posted by Old Pedant View Post
    Technically correct.

    But look at the mess it takes to invoke a function defined via prototype in any other way.
    Code:
    function Cat( name, breed )
    {
        this.name = name;
        this.breed = breed;
    }
    Cat.prototype.meow = function() { alert( this.name + " says meow" ); };
    
    var f = new Cat( "Fred", "xx" );
    f.meow();
    
    var g = {
        name : "George",
        breed : "Manx"
    };
    
    Cat.prototype.meow.bind( g )( ); // ugly, isn't it?
    if you do it like that, sure, but it need not be so brutal.


    5 simple ways:

    Code:
    function Cat( name, breed ){
        this.name = name;
        this.breed = breed;
    }
    
    function unbind(method){return Date.call.bind(method); } // Library unbind function:
    function purr() { alert( this.name + " purs loudly" ); };
    
    var cp=Cat.prototype,
      g = {
        name :  "George",
        breed : "Manx" ,
        purr2:  purr
    };
    
    cp.meow = function() { alert( this.name + " says meow" ); };
    cp.purr=purr;
    cp.bark=Cat.bark=function() { alert ( this.name + "  can't bark, only dogs do that" ); };
    var purr3=unbind(purr);
    
    
    // not so ugly, is it?
    purr3(g);
    cp.meow.call( g );
    purr.call( g );  
    Cat.bark.apply( g );  
    g.purr2( );
    of course, i agree that writing out xxx.prototype.call every time is a PITA...
    Last edited by rnd me; 12-26-2012 at 10:33 AM.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #12
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,700
    Thanks
    80
    Thanked 4,657 Times in 4,619 Posts
    LOL! No, it's not as ugly as my way. I'd say it's at least twice as ugly.

    But never mind, I"ll concede the point that there are many ways to disenteguate a feline.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #13
    New to the CF scene
    Join Date
    Dec 2012
    Posts
    3
    Thanks
    1
    Thanked 0 Times in 0 Posts
    Now I understand it a bit.
    Thank you all!


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •