Just JavaScript - The Prototype Mechanism |
Written by Ian Elliot | ||||
Friday, 05 December 2014 | ||||
Page 2 of 3
Improve efficiency using a prototypeWhere you do get an efficiency gain is when you supply a function as a property using a prototype. For example:
Now the prototype has a method that displays its own property.
Now both objects display the value 1 but they both make use of the same definition of myDisplay which is only stored in the prototype object. In fact this is the main problem that the prototype mechanism was invented to solve. In class-based languages methods that are defined in the class are not copied to every instance of the class - only the data is copied. That is, in class-based, object-oriented programming all instances share the common code of methods but have their own data. The prototype mechanism in JavaScript allows you to share a single implementation of methods between a set of objects. All you have to do is set up the prototype object with all the shared methods and then set this as the prototype for all the objects you create. Of course, if one of the objects defines its own method with the same name then the prototype method is shadowed. There is also the fact that you can use multiple prototype objects via the prototype chain. To a programmer familiar with class-based objects this looks a lot like either inheritance or multiple inheritance depending on whether or not the prototype objects form a natural hierarchy - i.e. does each one "extend" in some sense the previous one. There is one final subtle point concerning the use of this. In the definition of the prototype:
we have a reference to this.a. What does this reference? The good news is that it follows the usual logic. The this is set to the calling context. So if you call:
this is set to myProto. If you call:
this is set to myObject1 but myDisplay isn't an own property and so it is resolved by the prototype chain, i.e. myProto supplies the function. The this still references myObject1 but when myDisplay tries to access myObject1.a it can't find it and so the prototype chain is used again and this resolves to the a supplied by myProto. Now let's shadow the a property by creating an own property:
The first call to myDisplay has this set to myObject1 and myDisplay is supplied by myProto but myObject1.a exists as an own property so it displays 10. The second call works in the same way but myObject2.a isn't an own object and so is supplied by myProto. The rule is that this is set to the calling context of the object and any methods supplied by the prototype object are executed in this context. A Simple ExampleIf your object is a singleton, there will only ever be a single instance of the object, so you often don't need to worry about prototypes. In a typical JavaScript program most of the objects are singletons - the main exception being objects designed to store data. In this case there is often a lot to be gained from using a prototype. For example, a typical 2D point object might be defined as:
and a typical use might be:
If you want a second point you would define the whole thing over again - probably using an object factory or a constructor rather than manually:
If you wanted 5000 point objects then having the setxy function defined 5000 times, one for each instance is a little wasteful. A better solution is to set up a prototype object with the methods that a point object needs.
You could include the intial data variables x, y if you want to, or they could be created on the instances as own properties - it doesn't make a great deal of difference. Now you can create two point objects very easily:
Notice that in this case the call to setxy creates the two own properties x and y for us. In general it is better to create any variables either as own variables or as part of the prototype. The Extended Role Of the ConstructorIf you have followed the idea of the prototype object and the way it provides a delegation mechanism for any properties that are not defined on an object, be reassured that it really is this simple. However, there is a slightly more complicated way of setting an objects [[prototype]] property that was designed early in the life of JavaScript to provide something that looked like a class-based type and inheritance mechanism. A constructor is just a function that is called with the new operator and returns an object. The idea is that the constructor is a special sort of object factory. JavaScript takes this idea one step further and for some it is a step too far. The idea is that a constructor can be used to create many instances of an object. This is a bit like the way in class-oriented languages a class can be used to create many instances of an object. So a constructor can play the same role as class in that it weakly defines a "type" of object. Put simply, the assumption is that if a constructor creates lots of instances of an object then they can be regarded as being of the same type. In this sense the constructor plays the role of a class and it defines an object type. This isn't unreasonable in the sense that any object that a constructor creates has the same set of properties as all the others it creates and what properties an object has defines its type. If a constructor is so important in the life of an object, why not allow it to play a role in the setting of an object's prototype chain. This is again part of thinking of the constructor as if it defined a class - complete with a hierarchy of classes it inherits from. The constructor prototype mechanism is:
This makes sense if you want to regard the constructor as playing the same role as a class. Every object that the constructor produces has the same set of properties and the same prototype chain. As an example of this approach to setting the prototype we can reimplement the 2D point object. We can leave the definition of the point prototype object as it was:
Now we are going to use a constructor to create a point object:
Notice that now we have set the constructor's prototype property to the pointMethods object. Again it is important to stress that pointMethods is not the function's prototype. It will be the prototype object for any objects the constructor creates. For example:
Now both point1 and point2 have pointMethods as their prototype. You can, of course create the prototype object by direct assignment to the prototype property, and this is a very common idiom, but it suffers from not automatically collecting all of the instructions that create the prototype in one place. For example you could write:
and build up the prototype object one property or method at a time. |
||||
Last Updated ( Sunday, 10 May 2015 ) |