Basically is there a good elegant mechanism to emulate super with syntax that is as simple as one of the following
this.$super.prop()
Note that for the following implementation, when you are inside a method that is invoked via $super, access to properties while working in the parent class never resolve to the child class's methods or variables, unless you access a member that is stored directly on the object itself (as opposed to attached to the prototype). This avoids a slew of confusion (read as subtle bugs).
Update:
Here is an implementation that works without __proto__. The catch is that using $super is linear in the number of properties the parent object has.
function extend (Child, prototype, /*optional*/Parent) {
if (!Parent) {
Parent = Object;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
for (var x in prototype) {
if (prototype.hasOwnProperty(x)) {
Child.prototype[x] = prototype[x];
}
}
Child.prototype.$super = function (propName) {
var prop = Parent.prototype[propName];
if (typeof prop !== "function") {
return prop;
}
var self = this;
return function () {
var selfPrototype = self.constructor.prototype;
var pp = Parent.prototype;
for (var x in pp) {
self[x] = pp[x];
}
try {
return prop.apply(self, arguments);
}
finally {
for (var x in selfPrototype) {
self[x] = selfPrototype[x];
}
}
};
};
}
The following implementation is for browsers that support the __proto__ property:
function extend (Child, prototype, /*optional*/Parent) {
if (!Parent) {
Parent = Object;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
for (var x in prototype) {
if (prototype.hasOwnProperty(x)) {
Child.prototype[x] = prototype[x];
}
}
Child.prototype.$super = function (propName) {
var prop = Parent.prototype[propName];
if (typeof prop !== "function") {
return prop;
}
var self = this;
return function (/*arg1, arg2, ...*/) {
var selfProto = self.__proto__;
self.__proto__ = Parent.prototype;
try {
return prop.apply(self, arguments);
}
finally {
self.__proto__ = selfProto;
}
};
};
}
Example:
function A () {}
extend(A, {
foo: function () {
return "A1";
}
});
function B () {}
extend(B, {
foo: function () {
return this.$super("foo")() + "_B1";
}
}, A);
function C () {}
extend(C, {
foo: function () {
return this.$super("foo")() + "_C1";
}
}, B);
var c = new C();
var res1 = c.foo();
B.prototype.foo = function () {
return this.$super("foo")() + "_B2";
};
var res2 = c.foo();
alert(res1 + "\n" + res2);