I think the biggest reason we don't see a prototype template anymore is because the default syntax in Javascript is pseudo-classical aberration, not the more favorable Object.create. If you want to really see how the prototype shine is trying to find places where this feature is used. The following example is from the Dojo toolkit:
Caution I changed my mind a bit about how good this code is since I originally wrote this answer. Although the basic idea is still worth it, you have to be careful, you have methods that mutate the properties of the instance ("this"). This is because if you call a method in the delegation object through a delegate, then you can end up setting variables in the deletor instead of the delegate, and this can lead to a violation of some invariants if someone else gets access to the delegate, which is the last one .
The whole idea is 100% good because you have immutable objects.
Dojo defines a common store interface (with methods such as get (), add (), etc.) that can be used, for example, to abstract the REST API from the server. We would like to create a Cache function that receives any data store and returns a new version that caches any calls to the get () method (this allows us to separate the caching from the store-specific behavior of the actual get () implementation)
The first idea would include using the fact that Javascript is very dynamic to replace the get method:
//not the actual implementation. Things get more complicated w/ async code. var oldGet = store.get; store.get = function(id){ if(!cache[id]){ cache[id] = oldGet(id); } return cache[id]; }
However, this compresses the original object, so you can no longer access the original method, and also make it difficult to add other changes in parallel.
A second idea would be to create a more robust solution using delegation:
function Cache(obj){ this.obj = obj; } Cache.prototype = { get: function(){
This looks promising until you remember that the resulting Cache object must implement the storage interface. We could try adding all the methods manually:
Cache.prototype = { //... put: function(){ return this.obj.apply(this, arguments); }, //... }
but not only it would be cumbersome and error-prone (it’s so easy to forget something), it would not even be as powerful as the solution modifying the object, since we lose access to the methods in this original object, which is not a store .
Well, the way to do this “automatic delegation” is to inherit, but in this case it will seem useless, since you will need to create a new cache subclass for each possible storage class, or you will need some fancy combination of multiple inheritance. Enter prototype inheritance to save the day. We can easily create a new obejct that adds functionality to the old one without changing it, or we don’t have to bother with the hieharchies class
dojo.store.Cache = function(masterStore, cachingStore, options){
Where dojo.delegate is a function that creates a new object with all the properties in the second argument and whose prototype is the first argument.
Theoretical deviations from JS: prototype inheritance can be used even more aggressively in even more delegation scenarios in a language such as Self, which allows the use of several prototypes, as well as direct access and modification of prototypes at runtime. For example, you can implement the State pattern from GoF by delegating all the appropriate methods to the prototype and changing the prototype whenever the state changes.