Friday, 1 March 2013

Prototype in JavaScript

Few Important things before reading prototype :
  • The functions in JavaScript are objects and they contain methods and properties. Some of the common methods are apply() and call() and some of the common properties are length and constructor. Another property of the function objects is prototype.
  • prototype is the property of functional objects. 
  • Only functions and no other object can be used as a constructor in javascript .

1.  Extending an object by adding a custom method can be quite convenient, but it only applies to that particular object's instance. What if you wanted to modify the entire existing class to add new functionality? For this, we use the prototype property.

2.  Adding properties or methods to the prototype property of an object class makes those items immediately available to all objects of that class, even if those objects were created before the prototype property was modified.

3.  Note that adding a public property to a class of objects creates a single value which all instance objects share. However, modifying this value through this.globalPropertyName will result in a local public property of the object being created and set. Modifications to the class-wide property must be made through the prototype property of the class.

4.  Declaring javascript object methods in constructor or in prototype:

a)  If your methods do not use local variables defined in your constructor , then use the prototype approach.
b) If you're creating lots of Dogs, use  the prototype approach. This way, all "instances" (i.e. objects  created by the Dog constructor) will share one set of functions, whereas the constructor way, a new set of functions is created every time the Dog constructor is called, using more memory.

5. Inheritance :

a) You cause a class to inherit using  ChildClassName.prototype = new ParentClass();.
b) You need to remember to reset the constructor property for the class using ChildClassName.prototype.constructor=ChildClassName.
c) You can call ancestor class methods which your child class has overridden using the method.
d) Javascript does not support protected methods.
(For detailed study follow : this link )

6. To add a property or method to an entire class of objects, the prototype property of the object class must be modified. The intrinsic object classes in JavaScript which have a prototype property are:
Object.prototype — Modifies both objects declared through the explicit new Object(...) constructor and the implicit object {...} syntax. Additionally, all other intrinsic and user-defined objects inherit from Object, so properties/methods added/modified in Object.prototype will affect all other intrinsic and user-defined objects.
Array.prototype — modifies arrays created using either the explicit new Array(...) constructor or the implicit [...] array syntax.
String.prototype — modifies strings created using either the explicit new String(...) constructor or the implicit "..." string literal syntax.
Number.prototype — modifies numbers created using either the explicit new Number(...) constructor or with inline digits.
Date.prototype — modifies date objects created with either the new Date(...) constructor.
Function.prototype — modifies functions created using either the explicit new Function(...) constructor or defined inline with function(...){...}.
RegExp.prototype — modifies regular expression objects created using either the explicit new RegExp(...) constructor or the inline /.../ syntax.
Boolean.prototype — applies to boolean objects created using the explicit new Boolean(...) constructor or those created using inline true|false keywords or assigned as the results of a logical operator.
(For detailed study follow : this link)

7. Danger of adding methods to Object.prototype:
·         Object.prototype.length = function(){
    var count = -1;
    for(var i in this) count++;
    return count; //appendTo method brock.
           // Do not use this
Object.prototype.load = function () {};
   $(window).load(function () {
  alert('load event'); // never fired
Augmenting the Object.prototype object in that way is never recommended, because those properties will be inherited by a great number of objects -even also by some host objects-, and as you know, the primary concern is that they will be enumerated by the for-in statement. Some methods of jQuery liberary are incompatible with extending Object.prototype.
In ECMAScript 5, now a safer way exists, because we can now declare non-enumerable properties, for example:
Object.defineProperty(Object.prototype, 'foo', {
value: 'bar',
In the property descriptor -{ value: 'bar' }- we can specify property attributes, in the case of Value Properties as in the above example, we can specify the writable attribute, and the common configurable attribute (determines if a property can be re-configured -attribute changes- or deleted).
And we have also the enumerable attribute, which determines if the property will be enumerated by the for-in statement.
If we don't specify the attributes, they are false by default, the descriptor will look like:
  value: 'bar',
  writable: false,
  configurable: false,
  enumerable: false

So far we talked about various points, but from here we are concentrating only in enumeration.

8. About making properties non-enumerable:
Benefit of making properties non-enumerative- I think the main benefit is to be able to control what   shows up when enumerating an object's properties, such as for in or Object.keys().So normally, when people want to add a method to Object, such as a polyfill for some method not supported in old browsers, they modify the .prototype. But that makes the property enumerable and messes up what is returned in loops/keys collection (without using .hasOwnProperty).
So instead of something like:
Object.prototype.myMethod = function () {
you could use Object.defineProperty to explicitly say to have it not be enumerable:
Object.defineProperty(Object.prototype, 'myMethod', {
    value: function () {
    enumerable: false
That way, for example when you use for (var key in obj), "myMethod" won't be an item enumerated, and you won't have to worry about using .hasOwnProperty. The main problem with this is that some browsers don't support it of course: link and that not all libraries/code use it, so you can't always rely on external libraries/code to do use correctly and all the time.
You can access a non-enumerable property at any time you want, it just won't show up when enumerating the object's properties - that's the main point.
And I do believe that all "predefined" properties of objects are non-enumerable. By that, I really only mean native properties, not necessarily inherited or created. So with your example, pop and push will not be enumerated over, but Array.prototype.indexOf will be if it is created as a polyfill on an old browser that doesn't support that method...which of course, can be avoided by using Object.defineProperty like my example above. Another example is the length property, which is not enumerated over.
Here's an example in general: link
The use and definition of Object.keys is important: "Returns an array of a given object's own enumerable properties, in the same order as that provided by a for-in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well)." - from MDN . 

9. There are some details to be aware of:
  • Not all properties show up in a for-in loop. For example, the length (for arrays) and constructor properties will not show up. The properties that do show up are called enumerable. You can check which ones are enumerable with the help of the propertyIsEnumerable() method that everyobject provides.
  • Prototypes that come through the prototype chain will also show up, provided they are enumerable. You can check if a property is an own property versus prototype's using the hasOwnProperty() method.
  • propertyIsEnumerable() will return false for all of the prototype's properties, even those that are enumerable and will show up in thefor-in loop.
Let's see these methods in action. Take this simplified version of Gadget():
function Gadget(name, color) { = name; 
   this.color = color; 
   this.someMethod = function(){return 1;}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Creating a new object:
var newtoy = new Gadget('webcam', 'black');
Now if you loop using a for-in, you see of the object's all properties, including those that come from the prototype:
for (var prop in newtoy) { 
   console.log(prop + ' = ' + newtoy[prop]); 
The result also contains the object's methods (as methods are just properties that happen to be functions):
name = webcam
color = black
someMethod = function () { return 1; }
price = 100
rating = 3
If you want to distinguish between the object's own properties versus the prototype's properties, use hasOwnProperty(). Try first:
 >>> newtoy.hasOwnProperty('name')
>>> newtoy.hasOwnProperty('price')
false .

No comments:

Post a Comment