www.webdeveloper.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 19

Thread: Best way to create a reusable object/class

  1. #1
    Join Date
    Jun 2005
    Posts
    11

    Best way to create a reusable object/class

    Hey,
    I'm new to OOP in javascript.
    What I have been doing so far to make a "class"/Reusable object is this:

    PHP Code:
    function Dog(){
        
    this.name name;
        
        
    this.bark = function(){
            
    // some code
        
    }

    However, recently I have been reading a book on Javascript and it said that the problem with this way of doing it, is that the bark() function will be loaded into memory for each Dog object created this way, while the body of that function is the same for each object. There was an explanation on how it could be done better but I did not understand it fully.

    Let's say I want:
    - A Person class with a name property and a jump() method.
    - An animal class with a isMammal property and move() method.
    - A Dog class with a numberOfLegs property and a bark() method which is a subclass of Animal (thus inherits the isMammal property and move() method.
    - Each of those classes in its own file.

    What would these files look like when I do it the right way?

    This book I've been reading is actually pretty good, but at some points it's explanation is not rich enough.

    It explains that functions are objects and that objects in javascript are just key-value pairs. It says that each function has a prototype property which points to a blank Object(), but you can make it point to something else? or maybe I misunderstood it. I still don't understand how it really works. Maybe someone can give me a good link or explain me how the whole prototype thing works.

    Hope you can help me out, it would really help me to start understanding Javascript better in its entirety. Because most things I can get working now, but I want to know why it works and whether I'm doing it in an efficient way.

    Thanks in advance,
    Stefan

  2. #2
    Join Date
    Dec 2003
    Location
    Bucharest, ROMANIA
    Posts
    15,428
    JavaScript has no classes. It works only with objects. Objects can be created in several ways. mainly:

    literally (using JSON)
    Code:
    var myObject={
    property:'somevalue',
    method:function(){alert(this.property)}
    }
    // or
    var myObject={};
    myObject.property='somevalue';
    myObject.method=function(){alert(this.property)};
    using a constructor:
    Code:
    function myConstructor(value){
    this.property=value;
    this.method=function(){alert(this.property)}
    }
    var myObject=new myConstructor('somevalue');
    Now, if I well understood, you need to create dynamically different methods, for different objects, but using the same constructor. Is this what you want?:
    Code:
    function Person(name,method){
    this.name=name;
    this[method]=function(){alert(this.name)}
    }
    var John=new Person('John','shout');
    var Alice=new Person('Alice','say');
    John.shout();
    Alice.say();

  3. #3
    Join Date
    Jul 2003
    Location
    The City of Roses
    Posts
    2,503
    Quote Originally Posted by stefan2 View Post
    PHP Code:
    function Dog(){
        
    this.name name;
        
        
    this.bark = function(){
            
    // some code
        
    }

    ... the problem with this way of doing it, is that the bark() function will be loaded into memory for each Dog object created ... What would these files look like when I do it the right way?
    It would look like this:

    PHP Code:
    function Dog(name) {
        
    this.name name;
    }

    Dog.prototype.bark = function () {
        
    // some code
    }; 
    The "prototype" property is automatically created with each function, and when you do new Dog(), the new object will inherit from Dog.prototype. So every instance of Dog will inherit and share the same copy of the function "bark".

    Quote Originally Posted by stefan2 View Post
    ... A Dog class ... which is a subclass of Animal ...
    Inheritance in JavaScript can be an in-depth topic, because there are several techniques. But the most basic looks like this:

    PHP Code:
    function Animal() {
    }

    Animal.prototype.move = function () {
        
    // some code
    };

    function 
    Dog(name) {
        
    this.name name;
    }

    Dog.prototype = new Animal();

    Dog.prototype.bark = function () {
        
    // some code
    }; 
    We start with a basic "Animal" function, and we attach a "move" method to Animal's prototype, so every instance of Animal will inherit the move method. Then for "Dog", we replace the prototype object with an instance of Animal. That means every instance of Dog will also inherit the move method, because Dog instances inherit from Dog.prototype, and now Dog.prototype inherits from Animal.prototype.

    If you want to learn from two of the better JavaScript books, I'd recommend Object-Oriented JavaScript first, then JavaScript Patterns for more advanced stuff.
    for(split(//,'))*))91:+9.*4:1A1+9,1))2*:..)))2*:31.-1)4131)1))2*:3)"'))
    {for(ord){$i+=$_&7;grep(vec($s,$i++,1)=1,1..($_>>3)-4);}}print"$s\n";

  4. #4
    Join Date
    Mar 2011
    Posts
    61
    Here's another example.

    Code:
    // first create a Person constructor, which takes two arguments and sets them as properties of the created instance
    function Person(name, age){
     this.name = name;
     this.age = age;
    };
    // add a function to the prototype, so that it shares the function on all instances of Person.
    Person.prototype.sayName = function(){return 'Hi, I\'am '+this.name};
    
    // next create a Worker constructor
    function Worker(name, age, company){
     Person.call(this, name, age);         // call the Person contructor with the instance to be created as relevant object, so it can set the name and age properties.
     this.company = company;               // add another property
    }
    Worker.prototype = new Person;         // set the Worker prototype to the Person prototype
    Worker.prototype.constructor = Worker; // set the constructor back to Worker
    Worker.prototype.sayCompany = function(){return 'I work at '+this.company} // extend the Worker prototype
    Worker.prototype.sayName = function(){ //overwrite the sayName function
     return Person.prototype.sayName.call(this) +'. '+ this.sayCompany();      // call the Person.sayName, and add some
    };
    One thing to consider is that when inheriting from another constructor using Sub.prototype = new Base, can cause problems the Base constructor requires an argument.
    for example:
    Code:
    function Sub(){}.prototype = new function Base(date){date.getDay()}; // Error: undefined does not have the method getDay();
    That's why it's better to use an intermediate constructor.
    Code:
    function InterMediate(){};
    Intermediate.prototype = Base.prototype
    Sub.prototype = new Intermediate;
    Which can be used to create an extend function, which also points the constructor to the right function
    Code:
    var extend = (function extend(I){
     return function extend(A, B){
      I.prototype = B.prototype;
      A.prototype = new i;
      A.prototype.constructor = A;
     };
    }(function(){}));
    Code:
    //Worker.prototype = new Person;
    //Worker.prototype.constructor = Worker;
    // becomes:
    extend(Worker, Person);

  5. #5
    Join Date
    Jun 2005
    Posts
    11
    Thanks for the reactions.

    I got the answer to my question.
    PHP Code:
    function Dog(name) { 
        
    this.name name


    Dog.prototype.bark = function () { 
        
    // some code 
    }; 
    This way I can create 1000 Dog objects which all share the same function (in memory).

    Also thanks for the book suggestions. The book I was talking about actually was Javascript Patterns, which is a great book, but I'm missing some basics, so maybe I will buy the Object-Oriented Javascript book.

    Let's see if I understand it correctly now:
    If you do: Dog.prototype = ....
    - Then you're setting the prototype property of the Dog object.
    - The prototype property is pointing to an object, by default Object(), but you can set it to any other object.
    - You can add functions and properties to that object.
    - Each time a Dog object is created it gets all the functions and properties of the object that was set as prototype.
    Is this right?

    Thanks again all of you.

  6. #6
    Join Date
    Jul 2003
    Location
    The City of Roses
    Posts
    2,503
    Quote Originally Posted by stefan2 View Post
    Let's see if I understand it correctly now:
    If you do: Dog.prototype = ....
    - Then you're setting the prototype property of the Dog object.
    - The prototype property is pointing to an object, by default Object(), but you can set it to any other object.
    - You can add functions and properties to that object.
    - Each time a Dog object is created it gets all the functions and properties of the object that was set as prototype.
    Is this right?
    All correct. :-)
    for(split(//,'))*))91:+9.*4:1A1+9,1))2*:..)))2*:31.-1)4131)1))2*:3)"'))
    {for(ord){$i+=$_&7;grep(vec($s,$i++,1)=1,1..($_>>3)-4);}}print"$s\n";

  7. #7
    Join Date
    Jan 2007
    Location
    Wisconsin
    Posts
    2,120
    As much as I loathe the using the prototype property (it's ugly, roundabout, and unorganized looking), it not only comes with significant memory savings, but there's also a significant efficiency advantage when calling prototyped methods versus non-prototyped methods. In my benchmarks, it ranges between 13.5% and 21.7%.

    But, bear in mind that, while this is a really significant improvement percentage-wise, it's not a noticeable improvement unless you're writing incredibly "busy" code. If you're writing a game, for example, and tracking thousands or hundreds of thousands of objects, trying to call various methods on each of those objects hundreds or thousands of times per tick with 20 or 30 ticks/second, you may benefit from the 13% to 22% boost. And you may see even bigger gains if your application has started paging. Though, chances are your DOM/Canvas calls are the real overhead if you're pushing the limits.

    However, if you're NOT making in excess of 10 million method calls/second and are instead doing some simple AJAX stuff, polling for new message every 5 seconds or so, using the prototype isn't at all necessary. No one will notice a 22% efficiency gain on an overhead of 0.000022ms. And the same goes for the negligible amounts of extra memory you'll be consuming.


    Applications that are pushing the limits may very well see benefits from using the prototype version:
    Code:
    var ClassName = function() {
    }
    
    ClassName.prototype.method = function() {
    }

    However, most applications can stand to use the version that is, in my opinion, prettier and more organized:

    Code:
    var ClassName = function() {
      this.method = function() {
      }
    }
    One of the first things I was taught in my CS studies: The better solution is the one that best meets the applications specific needs. Sometimes it's efficiency, sometimes it's a small footprint, sometimes it's the solutions is fastest or easiest to implement, and sometimes it's just the code that's easiest to read and maintain.
    Jon Wire

    thepointless.com | rounded corner generator

    I agree with Apple. Flash is just terrible.

    Use CODE tags!

  8. #8
    Join Date
    Jul 2003
    Location
    The City of Roses
    Posts
    2,503
    Quote Originally Posted by svidgen View Post
    One of the first things I was taught in my CS studies: The better solution is the one that best meets the applications specific needs. Sometimes it's efficiency, sometimes it's a small footprint, sometimes it's the solutions is fastest or easiest to implement, and sometimes it's just the code that's easiest to read and maintain.
    Fortunately, these days we don't need to choose between readability and performance. There are libraries that will let you write code in the style you prefer, while still using prototypes under the hood.

    Here's one I wrote some time ago.

    PHP Code:
    var BaseFn;

    // Private scope
    (function () {
        
    BaseFn extendFunction.call(Object, {
            
    init: function () {
                
    // Stub
            
    }
        });

        function 
    extendFunction(overrides) {
            
    // Create subtype constructor
            
    function Subtype() {
                return 
    this.init.apply(thisarguments);
            }

            
    // Make subtype extendable
            
    Subtype.extend extendFunction;

            
    // Create subtype prototype that inherits from supertype prototype
            
    Subtype.prototype extendObject(this.prototypeoverrides);

            
    // Fix constructor property
            
    Subtype.prototype.constructor Subtype;

            return 
    Subtype;
        }

        function 
    extendObject(ooverrides) {
            
    // Spawn
            
    function F() {}
            
    F.prototype o;
            var 
    subtype = new F();

            
    // Augment
            
    if (overrides) {
                for (var 
    p in overrides) {
                    
    subtype[p] = overrides[p];
                }
            }

            
    // Reference supertype
            
    subtype.$super o;

            return 
    subtype;
        }
    }()); 
    Using this, our code from this post could look like this:

    PHP Code:
    var Animal BaseFn.extend({
        
    move: function () {
            
    // some code
        
    }
    });

    var 
    Dog Animal.extend({
        
    init: function (name) {
            
    this.$super.init.call(this);
            
    this.name name;
        },

        
    bark: function () {
            
    // some code
        
    }
    }); 
    for(split(//,'))*))91:+9.*4:1A1+9,1))2*:..)))2*:31.-1)4131)1))2*:3)"'))
    {for(ord){$i+=$_&7;grep(vec($s,$i++,1)=1,1..($_>>3)-4);}}print"$s\n";

  9. #9
    Join Date
    Jan 2007
    Location
    Wisconsin
    Posts
    2,120
    Neat. I hadn't tried anything like that yet. Hadn't really thought it was that important.

    Nice to see something like this in action though.
    Jon Wire

    thepointless.com | rounded corner generator

    I agree with Apple. Flash is just terrible.

    Use CODE tags!

  10. #10
    Join Date
    Jun 2005
    Posts
    11
    Yeah you got a point there.
    When I was doing Java programming at college, they taught us to write neat code rather than the most efficient code.

    I'm actually (trying) to make a RTS game, with possibly alot of objects on the field. So when I found out that the way I had been creating "reusable-objects" was not very efficient, I had to know how I could do it more efficiently.

    I actually have no idea whether creating a heavy game in Javascript/html5/css is even doable, there's so many things involved with RTS games. Drawing all units on the screen every so many times per second, keeping track of a grid to do path finding for all objects, collision detection, rotating images in the canvas (if you want 360 degree turning rather than a fixed set of directions), etc. Sometimes I start to think it's a bit too much to handle, but I don't really know.

    I know there are probably much better languages and libraries available for creating games, but I see it as an interesting project to do it with (mainly) Javascript. Also I actually like to write everything myself, its a better way to learn for sure, because you run into so many small problems while doing so, from which you really learn alot.

  11. #11
    Join Date
    Jul 2008
    Location
    urbana, il
    Posts
    2,787
    Quote Originally Posted by stefan2 View Post
    I actually have no idea whether creating a heavy game in Javascript/html5/css is even doable, there's so many things involved with RTS games. Drawing all units on the screen every so many times per second, keeping track of a grid to do path finding for all objects, collision detection, rotating images in the canvas (if you want 360 degree turning rather than a fixed set of directions), etc. Sometimes I start to think it's a bit too much to handle, but I don't really know.
    you'de have to do all those things in any language to make the game, javascript is just the open way of doing it.

    svg and webGL expose quite a bit of rendering capability.
    heck, css3 does quite a bit of neat stuff alone.

    lots of games were made in AS2, and AS2 is essentially strong typed javascript with a class library...

    for performance, web workers are much faster at crunching numbers and searching objects than normal browser javascript, but the message passing and file-loading can be cumbersome to work with. but, If you can base your main engine in worker threads, your game animations won't be as likely to slow down or drop frames since the animation and constant calculations are on different threads... boot up your worker, and fill it using messages, synching with the gui to transmit game events and state changes.


    having higher performance on the slow parts enables you to use easier coding patterns (like functional or oop) to create RADical solutions.

  12. #12
    Join Date
    Jan 2007
    Location
    Wisconsin
    Posts
    2,120
    For those interested in the real efficiency savings ...

    I re-ran my benchmarks (I had to!) in a slightly more controlled environment, under more fair, compartmentalized conditions, ensuring that new page-sessions were open for each set of tests. And I found that one of my previous results was not necessarily accurate. (It's possible that the statement was "accurate" under certain conditions. But, I couldn't say what those conditions would be.)

    I had previously stated, there's also a significant efficiency advantage when calling prototyped methods versus non-prototyped methods. In my benchmarks, it ranges between 13.5% and 21.7%. And at the the of that statement, I had run several permutations of the tests. But, I have since been unable to show any consistent difference. I would be interested to see others' benchmarks under various conditions. However, I've run iterative tests under fresh window loads with a variety of object instantiation syntaxes, and this particular point has proven to be mistaken.

    So, in general, given two objects:

    Code:
    var ClassA = function() {
    }
    ClassA.add = function(a,b) {
      return a + b;
    }
    var a = new ClassA();
    
    var ClassB = function() {
      this.add = function(a,b) {
        return a + b;
      }
    }
    var b = new ClassB();
    The following two calls are, according to my tests, of equivalent efficiency:

    Code:
    a.add(1,1);
    b.add(1,1);
    Possible explanation: This latest suite of tests dwarfs any difference in the method-call with other logic: a method wrapper for the benchmarking loop, modulo arithmetic to pick an object instance, and a incrementor (actually two, if you count the one running the benchmark loop), and the method logic itself (adding p1 + p2 and returning). However, if the difference is so easily dwarfed into total undectability, it's probably not worth noting.

    The object instantiation cost is much more significant, yielding a 51% savings using the prototype (a 106% performance hit by not using prototype). An object helper class, a bit simpler than the one Jeff Mott posted, shows no significant efficiency difference. And Jeff's example introduces about 15.8% efficiency during object instantiation over using the prototype directly (not sure where this efficiency hit could be occurring -- haven't really studied the code). I would estimate that the efficiency gap widens as the class methods become larger. Since I don't know where the efficiency hole in Jeff's code is, I can't say what would widen or shrink that gap.

    I haven't looked at any of these in terms of memory consumption. And all benchmarks were performed in Chrome on OS X. Based previous benchmarks for different constructs (such as array creation), I am assuming that the results are similar, with slightly varying magnitude/significance.

    So, stefan2 ... If you're attempting to perform hundreds of thousands of object instantiations per second, definitely use prototype. If you're instantiating a bunch of objects (even in the millions) all at once and then just calling their methods at a high rate, you're probably OK either way. But, you may run into memory problems in you have a lot of bulky objects, objects with many and/or large methods.

    Find a system like Jeff's. De-obfuscate it, if you need to. (It seems obfuscated to me.) And find that tiny 15% efficiency hole if it's causing you any trouble (it probably won't).

    ... that was fun.
    Jon Wire

    thepointless.com | rounded corner generator

    I agree with Apple. Flash is just terrible.

    Use CODE tags!

  13. #13
    Join Date
    Jul 2008
    Location
    urbana, il
    Posts
    2,787
    the code you posted is broken: a has no add method...

    keep in mind that there is a higher property-name resolution cost on prototypes than there is on own properties. If a prototype get chained 2 or 3 (or 20) levels deeps, there's a lot of potentials to strike off the list before the correct prototype appears.

    your two methods are identical pure functions, so there's no reason to tote them around with the objects.
    the main advantage of binding methods in-constructor is making use of the privileged pattern, aka having access to closure inside the constructor.

    if you don't need closure, but do need direct object association, use prototypes.
    if you don't need either (the example given doesn't), use a 3rd-party method container:
    Code:
    fn={
      add : function(b) {
        return this.a + b;
      }
    };//end fn
    
    
    alert(
    
      fn.add.call(
         {a:1},   2
      )
    
    ) //shows: 3

  14. #14
    Join Date
    Jun 2005
    Posts
    11
    I won't be needing that many objects, but I guess I can better do things the efficient way now, than rewriting my entire code of the game too make it run properly, in the end.

    Also I will be enclosing each constructor + prototype code into a separate file. At least for all the game-objects and the helper-objects like Vector, Table, Stack, etc. This way the prototype code isn't as chaotic, everything just has it's own file.

  15. #15
    Join Date
    Jan 2007
    Location
    Wisconsin
    Posts
    2,120
    Quote Originally Posted by rnd me View Post
    the code you posted is broken: a has no add method...
    Yup ... typo. The benchmarked code is correct.
    Jon Wire

    thepointless.com | rounded corner generator

    I agree with Apple. Flash is just terrible.

    Use CODE tags!

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

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
  •  
HTML5 Development Center



Recent Articles