Працюючи на основі відповідей, наданих geek_dave та charlysisto, я написав це, щоб додати this._super(funcName, ...)
підтримку в класах, які мають кілька рівнів успадкування. Це добре працювало в моєму коді.
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
var scope = null;
var scan = this.__proto__;
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === arguments.callee.caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
return scan.constructor.__super__[funcName].apply(this, _.rest(arguments));
};
Через рік я виправив деякі помилки і зробив все швидше. Нижче наведено код, який я використовую зараз.
var superCache = {};
Backbone.View.prototype._superFn = Backbone.Model.prototype._superFn = function(funcName, _caller) {
var caller = _caller == null ? arguments.callee.caller : _caller;
var scope = null;
var scan = this.__proto__;
var className = scan.constructor.className;
if (className != null) {
var result = superCache[className + ":" + funcName];
if (result != null) {
for (var i = 0; i < result.length; i++) {
if (result[i].caller === caller) {
return result[i].fn;
}
}
}
}
search: while (scope == null && scan != null) {
var names = Object.getOwnPropertyNames(scan);
for (var i = 0; i < names.length; i++) {
if (scan[names[i]] === caller) {
scope = scan;
break search;
}
}
scan = scan.constructor.__super__;
}
var result = scan.constructor.__super__[funcName];
if (className != null) {
var entry = superCache[className + ":" + funcName];
if (entry == null) {
entry = [];
superCache[className + ":" + funcName] = entry;
}
entry.push({
caller: caller,
fn: result
});
}
return result;
};
Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
var args = new Array(arguments.length - 1);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i + 1];
}
return this._superFn(funcName, arguments.callee.caller).apply(this, args);
};
Потім дано цей код:
var A = Backbone.Model.extend({
go1: function() { console.log("A1"); },
go2: function() { console.log("A2"); },
});
var B = A.extend({
go2: function() { this._super("go2"); console.log("B2"); },
});
var C = B.extend({
go1: function() { this._super("go1"); console.log("C1"); },
go2: function() { this._super("go2"); console.log("C2"); }
});
var c = new C();
c.go1();
c.go2();
Результат у консолі такий:
A1
C1
A2
B2
C2
Цікаво те, що виклик класу C this._super("go1")
сканує ієрархію класів, поки він не потрапить у клас A. Інші рішення цього не роблять.
PS Розкомментируйте className
записи визначень класів, щоб уможливити кешування _super
пошуку. (Припущення полягає в тому, що ці назви класів будуть унікальними в додатку.)