JavaScript Object and Prototypes

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Frinavale
    Recognized Expert Expert
    • Oct 2006
    • 9749

    JavaScript Object and Prototypes

    JavaScript is a very strange place for me...

    So, I decided that, before I attempt to create an Object, I should first learn about Objects. I had actually created one before with the help of a tutorial. The tutorial was complicated because showed me how to create a JavaScript Object that is a representation my .NET Object and how to get the two to "work together as one".... apparently the tutorial was not very clear about what was going on in the JavaScript Object...and even with my extensive commenting of the JavaScript Object I still didn't "really" know what was going on...at the time I was more interested in the .NET concepts than the JavaScript techniques being used in the tutorial.

    Anyways, I started with the basics: how do I create a JavaScript Object.
    To my surprise all functions were Objects, all Objects were Functions and I was not pleased with this new way of thinking because it's really strange...but it's just how things are.

    The next thing I did was try to figure out what I had done to create the JavaScript Object in the tutorial. This Object uses the prototype property (which is apparently an Object and is a property of all functions) to add functions and properties to the Object.

    So I started playing around with a silly little (uncomplicated) Object of my own...

    Please see the comments in the following code for what I'm confused about:

    Code:
    <html>
    <body>
    
    <script type="text/javascript">
    
    /*Welcome to my little Foo Class experimentation.
    The following function is a "constructor function", 
    that will create an instance of my Foo Object*/
    function Foo(firstNumber,secondNumber){
      this.a = firstNumber; //"a" is now a property of the Foo Object
      this.b = secondNumber;//"b" is now a property of the Foo Object
      this.Multiply = function(){return this.a * this.b;}//Multiply is now a method for my Foo Object
      this.Divide = function(){return "you're in Foo's Divide function";}
      //The Divide method is NOT overwritten by the Divide method in the prototype Object
    
    /*
    The following does not work.
    Even though it does work when I use the same sort of 
    thing to "overwrite" the prototype Object.
    
    Why??
    */
    
      /*a: firstNumber,
      b: secondNumber,
      Multiply: function(){return this.a * this.b;}*/
    };
    
    //This was my first experiment:
    //I used the prototype property to add the Divide method to the Foo Class
    /*Foo.prototype.Divide = function(){return this.a/this.b;};*/
    
    //This is my second experiment:
    //overwrite the prototype Object
    //This works fine but...
    //What is with the colons (:) and commas (,)??
    //I don't get it
    Foo.prototype = {
        Add: function(){return this.a + this.b},
        Divide: function(){return this.a/this.b;}
    };
    
    var instanceOfFoo = new Foo(2,3);
    
    //JavaScript couldn't find Add in the Foo class
    //it looks to the prototype Object and finds it there
    document.write(instanceOfFoo.Add());
    document.write("<br />");
    document.write(instanceOfFoo.Multiply());
    document.write("<br />");
    
    //The Divide method is found in the Foo class and is used 
    //instead of the one defined in the prototype
    document.write(instanceOfFoo.Divide());
    document.write("<br />");
    
    //The following doesn't work...
    //how do you access the Divide method in the prototype???
    //document.write(instanceOfFoo.prototype.Divide());
    //document.write("<br />");
    document.write("<br />");
    
    
    var anotherInstanceOfFoo = new Foo(10,2);
    document.write(anotherInstanceOfFoo.Add());
    document.write("<br />");
    document.write(anotherInstanceOfFoo.Multiply());
    document.write("<br />");
    document.write(anotherInstanceOfFoo.Divide());
    document.write("<br />");
    document.write("<br />");
    
    instanceOfFoo.newProperty = "instanceOfFoo's property";//adds a property named "newProperty" to the instanceOfFoo live Object.
    document.write(instanceOfFoo.newProperty);
    document.write("<br />");
    document.write(anotherInstanceOfFoo.newProperty);//is undefined because it is only available to the instanceOfFoo live Object
    document.write("<br />");
    document.write("<br />");
    
    //Adding a property named "newProperty" to the prototype object of the Foo class
    //This makes it available to all instances of the Foo class (live ones too) 
    Foo.prototype.newProperty ="newly added property to prototype which is available to all 
    instances of Foo.";
    
    //It's interesting that the original value for the "newProperty" property is kept
    document.write(instanceOfFoo.newProperty);
    document.write("<br />");
    document.write(anotherInstanceOfFoo.newProperty);//now contains a value
    document.write("<br />");
    
    </script>
    
    </body>
    </html>

    Thanks for your help clarifying the questions in the above posted code!

    -Frinny
  • gits
    Recognized Expert Moderator Expert
    • May 2007
    • 5390

    #2
    ok .... let's have a closer look at it :) ...

    typically you create a constructor like this:

    Code:
    function MY_OBJ() {
        this.prop = 'foo';
        this.func = function() { //whatever code };
    }
    
    // use the constructor
    var my_obj = new MY_OBJ;
    you cannot mix that with the : notation of properties ... the properties are declared with this.prop in the above case, and need explicit assignments.

    Now you could even create a new object like this literally:

    Code:
    var foo = {
        a: 'some_value',
        b: function() { // whatever code }
    };
    here you create an instance of an object directly and you declare the properties a and b ... where b stores a reference to the function-code that is assigned to it. note: when you have a look at this ... this is where JSON is not far away ;) just have that as a string from a response and eval it and you have a native js-object ready for use.

    so when you do:

    Code:
    some_obj.prototype = {
        // whatever 
    };
    you create a new prototype-obj with the properties/methods you want the some_obj to have.

    the 'classical' way to do that is:

    Code:
    some_obj.prototype.my_new_function = function() {
        // function's code
    }
    so you just extend the prototype of the obj with just one property/method instead of overwriting the entire prototype. now you are asking how to call a method ... this is quite simple. when you have an instance you just call it like this:

    Code:
    obj_instance.method_name();
    when you want to use the method without an instance, then just use:

    Code:
    constructor_name.prototype.method_name();
    i hope this helps you? :)

    kind regards

    PS: be aware of the use of the this keyword when working with javascript object ... this always relates to the caller of a function ... so that might be tricky when starting to use objects in JavaScript.

    Comment

    • Frinavale
      Recognized Expert Expert
      • Oct 2006
      • 9749

      #3
      Originally posted by gits
      ok .... let's have a closer look at it :) ...

      you cannot mix that with the : notation of properties ... the properties are declared with this.prop in the above case, and need explicit assignments.
      What is the name of the ":" notation so that I can look this up?

      Originally posted by gits
      Now you could even create a new object like this literally:

      Code:
      var foo = {
          a: 'some_value',
          b: function() { // whatever code }
      };
      where you create an instance of an object directly and...
      Ok, "overwritin g" makes sense to me now, thanks.

      Originally posted by gits
      now you are asking how to call a method ... this is quite simple. when you have an instance you just call it like this:

      Code:
      obj_instance.method_name();
      when you want to use the method without an instance, then just use:

      Code:
      constructor_name.prototype.method_name();
      This is not exactly what I was asking.

      I've defined 2 versions of the Divide() method: one in the Foo class and the other is in Foo's prototype.

      The Divide() method in the Foo class simply returns a String stating that "you're in Foo's Divide function".

      The Divide() method in Foo's prototype divides "a" property by "b" property.

      I'm wondering how to call the Divide() method in the prototype for a live instance of Foo.....not how to statically call the Divide() method in the prototype...I don't know if I'm being clear here so if you don't understand my question I can try and restate it.

      Comment

      • gits
        Recognized Expert Moderator Expert
        • May 2007
        • 5390

        #4
        the prototype is first parsed and later when you create the instance then the member-variables are allocated. when you have a prototype-property for the obj and then create a member directly this will drop the reference to the prototypes method for this obj. so the member will 'override' the prototype for this instance ... you only could call it staticly

        using the prototype is to prefer because members will always alloc memory while the prototype is read and parsed only once.

        kind regards

        Comment

        • gits
          Recognized Expert Moderator Expert
          • May 2007
          • 5390

          #5
          ahh ... and i don't know whether there is a name for the : - notation ... it could only be used when you create JavaScript-objects through the literals {}:

          Code:
          var a = {};
          
          // is equivalent to:
          
          var a = new Object;
          kind regards

          Comment

          • Frinavale
            Recognized Expert Expert
            • Oct 2006
            • 9749

            #6
            Originally posted by gits
            the prototype is first parsed and later when you create the instance then the member-variables are allocated. when you have a prototype-property for the obj and then create a member directly this will drop the reference to the prototypes method for this obj. so the member will 'override' the prototype for this instance ... you only could call it staticly
            Ok I didn't know this. In fact I had a completely different view on this. I thought that the JavaScript engine would fist search the Object for the property/method and if it couldn't find it it would then search the prototype....

            I thought the reason for why I couldn't get to the prototype's method was because the JavaScript engine found the method in the Object and simply used that method.

            Are you saying that if there is a method defined in the Object, that there is no possible way to access a method with the same name in the prototype because it's being overwritten?

            This honestly seems a bit backwards to me....I was thinking that I could use the prototype object to "extend" functionality of existing objects....but if I can't overwrite the existing methods then this idea obviously wont work.

            This is disappointing
            Originally posted by gits
            using the prototype is to prefer because members will always alloc memory while the prototype is read and parsed only once.
            This will let allow for extended functionality on existing methods/properties as well...?? (testing)

            Comment

            • gits
              Recognized Expert Moderator Expert
              • May 2007
              • 5390

              #7
              not exactly ... it is the following way:

              1. script is loaded and parsed ... so even all prototypes are parsed for the classes first - all prototype-props become part of this for the constructor
              2. now you create an instance -> the constructor is executed ... and the new function is assigned to the name that first had a reference to the prototypes method.

              to overwrite you have to create a instance first and then overwrite the method for that instance or make use of inheritance and use different classes:

              Code:
              function FOO() {}
              
              FOO.prototype.my_func = function() {};
              
              function CHILD_FOO() {}
              
              CHILD_FOO.prototype = new FOO;
              
              CHILD_FOO.prototype.constructor = CHILD_FOO;
              
              CHILD_FOO.prototype.my_func = function() {};
              
              var child_foo = new CHILD_FOO;

              Comment

              • Frinavale
                Recognized Expert Expert
                • Oct 2006
                • 9749

                #8
                I'll try your example in a sec...

                But this is working:
                Code:
                <html>
                <body>
                
                <script type="text/javascript">
                
                function Foo(firstNumber,secondNumber){
                  this.a = firstNumber; //"a" is now a property of the Foo Object
                  this.b = secondNumber;//"b" is now a property of the Foo Object
                };
                Foo.prototype = {
                    Add: function(){return this.a + this.b;},
                    Divide: function(){return this.a/this.b;},
                    Multiply: function(){return this.a * this.b;}
                };
                
                function GrownUpFoo(firstNumber, secondNumber, thirdNumber){
                   this.Foo = new Foo(firstNumber, secondNumber);
                   this.c = thirdNumber;
                };
                
                GrownUpFoo.prototype = {
                     Multiply: function(){return this.Foo.a * this.Foo.b * this.c;}
                };
                
                
                var instanceOfGrownUpFoo = new GrownUpFoo(2,3,4);
                document.write(instanceOfGrownUpFoo.Multiply());
                document.write("<br />");
                document.write(instanceOfGrownUpFoo.Foo.Multiply());
                
                </script>
                
                </body>
                </html>

                Comment

                • Frinavale
                  Recognized Expert Expert
                  • Oct 2006
                  • 9749

                  #9
                  Originally posted by gits
                  not exactly ... it is the following way:

                  1. script is loaded and parsed ... so even all prototypes are parsed for the classes first - all prototype-props become part of this for the constructor
                  2. now you create an instance -> the constructor is executed ... and the new function is assigned to the name that first had a reference to the prototypes method.

                  to overwrite you have to create a instance first and then overwrite the method for that instance or make use of inheritance and use different classes:
                  Ok that's basically what I did in my experiment.
                  This method also allows me to overwrite the method defined in the "class" function of the base...
                  Code:
                  <html>
                  <body>
                   
                  <script type="text/javascript">
                   
                  function Foo(firstNumber,secondNumber){
                    this.a = firstNumber; //"a" is now a property of the Foo Object
                    this.b = secondNumber;//"b" is now a property of the Foo Object
                    this.Multiply = function(){return this.a * this.b;};
                  };
                  Foo.prototype = {
                      Add: function(){return this.a + this.b;},
                      Divide: function(){return this.a/this.b;},
                  };
                   
                  function GrownUpFoo(firstNumber, secondNumber, thirdNumber){
                     this.Foo = new Foo(firstNumber, secondNumber);
                     this.c = thirdNumber;
                  };
                   
                  GrownUpFoo.prototype = {
                  //The following agumetns the multiply method
                       Multiply: function(){return this.Foo.Multiply() * this.c;}
                  };
                   
                   
                  var instanceOfGrownUpFoo = new GrownUpFoo(2,3,4);
                  document.write(instanceOfGrownUpFoo.Multiply());
                  document.write("<br />");
                  document.write(instanceOfGrownUpFoo.Foo.Multiply());
                   
                  </script>
                   
                  </body>
                  </html>

                  Comment

                  • Frinavale
                    Recognized Expert Expert
                    • Oct 2006
                    • 9749

                    #10
                    Thanks a lot for your help Gits!
                    I have a much better understand about the JavaScript engine, JavaScript Objects, and even inheritance in JavaScript.

                    :)

                    -Frinny

                    Comment

                    • Frinavale
                      Recognized Expert Expert
                      • Oct 2006
                      • 9749

                      #11
                      Just to recap everything I learned here:

                      There are 2 ways to define and use a class in JavaScript.
                      The fist allows you to define a class and use it to create multiple instances (objects) of it.

                      The other defines a class and creates an instance of it at the same time (literally) but cannot be used to create more instances of the class..

                      To create a class that you can create multiple instances of you need to define it like:
                      Code:
                       function MY_CLASS() {
                          this.aProperty = 'foo';
                          this.aFunction = function() { return "something"; };
                      }
                      Then you can use it to create multiple instances:
                      Code:
                      var firstMyClassInstance = new MY_CLASS();
                      var secondMyClassInstance = new MY_CLASS();
                      var thirdMyClassInstance = new MY_CLASS();
                      If you don't need to more than one instance of the class, you can define one and create an instance of it at the same time by:
                      Code:
                      //the variable anObject is an object that is an instance of the class defined inline/litterally
                      var anObject= {
                          aProperty: 'some_value',
                          aFunction: function() { return "something";}
                      };
                      Also the prototype property is an Object that is part of every Object.
                      It is used to provide additional properties/methods to an Object but is not to be used to "overwrite" any properties/methods in the class that is a part of. The JavaScript engine loads and parses the prototype Object and anything defined within the prototype becomes part the Object that the prototype belongs to.

                      This is why my attempts to overwrite the method defined in the "class" function with a method defined in the prototype property was failing.

                      You cannot use the prototype property like inheritance, to overwrite the methods in the class that is is a part of.

                      You have to properly create a new derived class that inherits the first class in order to extend functionality in the base class.

                      Comment

                      • gits
                        Recognized Expert Moderator Expert
                        • May 2007
                        • 5390

                        #12
                        no problem ... glad i could have been of some help :)

                        kind regards,
                        gits

                        Comment

                        • gits
                          Recognized Expert Moderator Expert
                          • May 2007
                          • 5390

                          #13
                          Originally posted by Frinavale
                          Also the prototype property is an Object that is part of every Object.
                          It is used to provide additional properties/methods to an Object but is not to be used to "overwrite" any properties/methods.
                          that's right except when you use inheritance ... as you see in my previous example ... the inheritance was made by overwriting the prototype of the child-obj with a new instance of the parent-class and then you could overwrite the inherited method with a new one ... in the child-obj's class

                          kind regards

                          Comment

                          • gits
                            Recognized Expert Moderator Expert
                            • May 2007
                            • 5390

                            #14
                            and just one more note for optimizing it a bit: when you create an instance without any parameters for the constructor then you might leave out the brackets ... this avoids the parsing of an empty args list for the parser and performs better ;)

                            Comment

                            • Frinavale
                              Recognized Expert Expert
                              • Oct 2006
                              • 9749

                              #15
                              Originally posted by gits
                              that's right except when you use inheritance ... as you see in my previous example ... the inheritance was made by overwriting the prototype of the child-obj with a new instance of the parent-class and then you could overwrite the inherited method with a new one ... in the child-obj's class

                              kind regards

                              Haha, don't try and confuse me now, I've finally got it!
                              :)

                              The only way to overwrite a method defined in a "class" function is to create a new "child-class" function. This child class is able to overwrite the methods in the parent-class.

                              Comment

                              Working...