Basically is there a good elegant mechanism to emulate super
with syntax that is as simple as one of the following
this.$super.prop()
this.$super.prop.apply(this, arguments);
Criteria to uphold are :
this.$super
must be a reference to the prototype. i.e. if I change the super prototype at run-time this change will be reflected. This basically means it the parent has a new property then this should be shown at run-time on all children through super
just like a hard coded reference to the parent would reflect changesthis.$super.f.apply(this, arguments);
must work for recursive calls. For any chained set of inheritance where multiple super calls are made as you go up the inheritance chain, you must not hit the recursive problem.Base.prototype.f.apply(this, arguments);
defeats the point.The naive implementation would be something like this.
var injectSuper = function (parent, child) {
child.prototype.$super = parent.prototype;
};
But this breaks condition 2.
The most elegant mechanism I've seen to date is IvoWetzel's eval
hack, which is pretty much a JavaScript preprocessor and thus fails criteria 4.
I don't think there is a "free" way out of the "recursive super" problem you mention.
We can't mess with the this
because doing so would either force us to change prototypes in a nonstandard way, or move us up the proto chain, losing instance variables. Therefore the "current class" and "super class" must be known when we do the super-ing, without passing that responsibility to this
or one of its properties.
There are many some things we could try doing but all I can think have some undesireable consequences:
Add extra info when calling the super method
$super(CurrentClass).method.call(this, 1,2,3)
This forces us to duplicate the current class name (so we can look up its superclass in some super dictionary) but at least it isn't as bad as having to duplicate the superclass name, (since coupling against the inheritance relationships if worse then the inner coupling with a class' own name)
//Normal Javascript needs the superclass name
SuperClass.prototype.method.call(this, 1,2,3);
While this is far from ideal, there is at least some historical precedent from 2.x Python. (They "fixed" super for 3.0 so it doesn't require arguments anymore, but I am not sure how much magic that involved and how portable it would be to JS)
Edit: Working fiddle
var superPairs = [];
// An association list of baseClass -> parentClass
var injectSuper = function (parent, child) {
superPairs.push({
parent: parent,
child: child
});
};
function $super(baseClass, obj){
for(var i=0; i < superPairs.length; i++){
var p = superPairs[i];
if(p.child === baseClass){
return p.parent;
}
}
}