I think the biggest reason that we don't see more of the prototypal pattern directly is that the default syntax in Javascript is that pseudo-classical aberration instead of the more favourable Object.create. If you want to really see the prototypal patter shining search for places where this function is used. The following example comes from the Dojo toolkit:
Caveat: I kind of changed my mind about how good this kind of code is since back when I originally wrote this answer. While the basic idea still stands, you should be careful it you have methods that mutate instance ("this") properties. This is because if you invoke a method in the delegate object via the delegator then you might end up setting variables in the delegator instead of in the delegate and that might break some invariants if someone else ends up accessing the delegate directly latter on.
The whole idea is 100% fine you you have immutable objects though.
Dojo defines a general store interface (with methods like get(), add(), etc) that can be used, for example, to abstract a REST API from the server. We would like to create a Cache function that receives any datastore and returns a new version that caches any calls to the get() method (this allows us to decouple the caching from the store-specific behaviour of implementing the actual get())
A first idea would involve using the fact the Javascript is highly dinamic 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 clobbers the original object so you can't access the original method anymore and also makes it trickier to add other modifications in parallel.
A second idea would be to make a more robust solution using delegation:
function Cache(obj){
this.obj = obj;
}
Cache.prototype = {
get: function(){
//do things involving this.obj...
}
};
This looks promising, until you remember that the resulting Cache object needs to implement the store interface. We could try adding all the methods by hand:
Cache.prototype = {
//...
put: function(){ return this.obj.apply(this, arguments); },
//...
}
but not only would that be cumbersome and error prone (its so easy to forget something) it would not even be as powerful as the object-modifying solution since we lose access to methods in that original object that aren´t from the store interface.
Well, the way to do this kind of "automatic delegation" is inheritance, but it would initialy seem useless in this case since you would need to create a new cache subclass for every possible store class or you would need some sort of fancy multiple-inheritance mixin. Enter prototypal inheritance to save the day. We can easily make a new obejct that adds functionality to an old one without modifying it or having to fiddle with the class hieharchies
dojo.store.Cache = function(masterStore, cachingStore, options){
//...
return dojo.delegate(masterStore, {
//...
get: function(id, directives){
//...
}
//...
}
}
Where dojo.delegate is a function that creates a new object with all the properties in the second argument and whose prototype will be the first argument.
Non JS theoretical ramblings: Prototypal inheritance can be used even more agressively in even more delegation scenarios in a language like Self that allows multiple prototypes and also direct access and modification of prototypes at runtime. For example, it is possible to implement the State pattern from the GoF by delegating all suitable methods to a prototype and changing the prototype whenever the state changes.