CodingBison

JavaScript does not support classes. However, JavaScript functions come with a prototype property and we can use this prototype property as a basis to form JavaScript classes.

Note that the prototype property is different from Function.prototype. All functions inherit their properties and methods from Function.prototype. Along the similar lines, if we use a function as a constructor, then all the objects derived from the function get to inherit properties and methods from the prototype property of the function.

Let us begin by examining the prototype property of a simple function. We provide an example below that looks at the prototype property of a simple function, dummyF().

 <!doctype html>
 <html>
 <div id="idDiv"></div>

 <script type="text/javascript">
 // Get a handle of the div element.
 var elem = document.getElementById("idDiv");

 // Define a dummy function.
 function dummyF(doer) {return doer;}

 // Print all (enumerable) properties.
 var prop = Object.getOwnPropertyNames(dummyF.prototype);
 for (var item in prop) {
     var x = "", i = 0;
     var attr = Object.getOwnPropertyDescriptor(dummyF.prototype, prop[item]);
     elem.innerHTML += "Name: " + prop[item] + ", Value: " + dummyF.prototype[prop[item]] + "<br>";
     for (var innerItem in attr) {
         if (innerItem == "value") {continue;} 
         if (i++ != 0) {x += ", ";}  // For Formatting.
         x += (innerItem + ": " + attr[innerItem]);
     }
     elem.innerHTML += "Name: " + prop[item] + ", Attributes: " + x + "<br>";
 }

 // Print object-level control information. 
 elem.innerHTML += "Extensible attribute: " + Object.isExtensible(dummyF.prototype); 
 elem.innerHTML += "<br> Object IsSealed: " + Object.isSealed(dummyF.prototype);
 elem.innerHTML += "<br>Object IsFrozen: " + Object.isFrozen(dummyF.prototype);

 </script>
 </html>

Here is the output of the above example. The output shows that the function's prototype property (dummyF.prototype) is an object in itself and has just one property: constructor. Now, this property has an enumerable value of "false" and therefore, using a for/in loop would not show this property in the loop. The fact that the dummyF.prototype has a constructor indicates that we can use the function as a basis to form new objects.

 Name: constructor, Value: function dummyF(doer) { return doer; }
 Name: constructor, Attributes: configurable: true, enumerable: false, writable: true
 Extensible attribute: true
 Object IsSealed: false
 Object IsFrozen: false

As noted earlier, when we use a function as a constructor, then objects created from the constructor inherit methods from the function's prototype property (e.g. dummyF.prototype). Thus, if we intend to use a function as a constructor, then using its prototype property, we can conveniently add methods that characterize the class of objects. With this, all the objects inherited from this function would automatically inherit these added methods. By convention, we keep the first letter of the constructor function in upper case.

To define a new object, we can use the "new" keyword to create an instance from the constructor function; the "new" keyword invokes the constructor method defined by the respective prototype (e.g. dummyF.prototype).

Here is a simple example that uses MagicBeing() function as a constructor to create a new object. We add methods to this constructor function and these methods become available to objects derived from this constructor.

 <!doctype html>
 <html>
 <div id="idDiv"></div>
 <script type="text/javascript"> 
 // Get a handle of the div element.
 var elem = document.getElementById("idDiv");

 // Define a function to return action of magical beings!
 function MagicBeing (argName, argAction) {
     elem.innerHTML += "Initializing object from Constructor...<br>";
     this.beingName = argName;
     this.beingAction = argAction;
 }

 // Method to add "beingLocation" property to the object.
 MagicBeing.prototype.addLocation = function (location) {
     elem.innerHTML += "<br>Adding beingLocation property...<br>";
     this.beingLocation = location;
 };

 // Method to print object properties (except functions).
 MagicBeing.prototype.printBeing = function () {
     elem.innerHTML += ("<br>Printing the object...<br>");
     for (var item in this) {
         if ((typeof this[item]) == "function") continue; //Skip functions
         elem.innerHTML += item + ": " + this[item] + "<br>";
     }
 };

 // Create a new Object.
 varGriffin = new MagicBeing("griffin", "fly", "Sky");
 varGriffin.printBeing();
 varGriffin.addLocation("Sky");
 varGriffin.printBeing();
 </script>
 </html>

The output (provided below) demonstrates that when we add methods to MagicBeing.prototype, these methods become available to objects derived from the MagicBeing constructor. This is similar to the case of adding methods to Array.prototype and these methods, then become available to all Array objects (aka arrays).

 Initializing object from Constructor...

 Printing the object...
 beingName: griffin
 beingAction: fly

 Adding beingLocation property...

 Printing the object...
 beingName: griffin
 beingAction: fly
 beingLocation: Sky

It is easy to dynamically add properties to the prototype itself. Here is an extension of the earlier example.

 <!doctype html>
 <html>
 <div id="idDiv"></div>
 <script type="text/javascript"> 
 // Get a handle of the div element.
 var elem = document.getElementById("idDiv");

 // Define a function to return action of magical beings!
 function MagicBeing (argName, argAction) {
     elem.innerHTML += "Initializing object from Constructor... <br>";
     this.beingName = argName;
     this.beingAction = argAction;
 }

 // Dynamically add properties to this object 
 MagicBeing.prototype.addPropertyDynamically = function (name, value) {
     elem.innerHTML += "Adding a new property dynamically... <br>";
     this[name] = value;
 };

 // Method to print object properties (except functions)
 MagicBeing.prototype.printBeing = function () {
     elem.innerHTML += "<br>Printing the object...<br>";
     for (item in this) {
         if ((typeof this[item]) == "function") continue; //Skip functions.
         elem.innerHTML += item + ": " + this[item] + "<br>";
     }   
 };

 // Create a new Object.
 varGriffin = new MagicBeing("griffin", "fly");
 varGriffin.printBeing();
 varGriffin.addPropertyDynamically("beingLocation", "Sky");
 varGriffin.addPropertyDynamically("beingDescription", "Head of an eagle, body of a lion");
 varGriffin.addPropertyDynamically("beingExistence", "Mythical");
 varGriffin.printBeing();
 </script>
 </html>

And, here is the output:

 Initializing object from Constructor... 

 Printing the object...
 beingName: griffin
 beingAction: fly
 Adding a new property dynamically... 
 Adding a new property dynamically... 
 Adding a new property dynamically... 

 Printing the object...
 beingName: griffin
 beingAction: fly
 beingLocation: Sky
 beingDescription: Head of an eagle, body of a lion
 beingExistence: Mythical




comments powered by Disqus