Лучший способ вызвать метод суперкласса в ExtJS
-
19-09-2019 - |
Вопрос
Вся документация ExtJS и примеры, которые я прочитал, предполагают вызов методов суперкласса, подобных этому:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
MyApp.MyPanel.superclass.initComponent.call(this);
}
});
Я использую этот шаблон уже довольно давно, и основная проблема заключается в том, что когда вы переименовываете свой класс, вам также приходится изменять все вызовы методов суперкласса.Это довольно неудобно, часто я забываю, и тогда мне приходится выслеживать странные ошибки.
Но, читая источник Ext.extend()
Я обнаружил, что вместо этого я мог бы использовать superclass()
или super()
методы, которые Ext.extend()
добавляет к прототипу:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
this.superclass().initComponent.call(this);
}
});
В этом коде переименовать MyPanel во что-то другое просто - мне просто нужно изменить одну строку.
Но у меня есть сомнения...
Я нигде не видел, чтобы это было задокументировано, и старая мудрость гласит, что я не должен полагаться на недокументированное поведение.
Я не нашел им ни единого применения
superclass()
иsupr()
методы в исходном коде ExtJS.Зачем создавать их, если вы не собираетесь их использовать?Может быть, эти методы использовались в какой-то более старой версии ExtJS, но сейчас устарели?Но это кажется такой полезной функцией, почему вы отказываетесь от нее?
Итак, должен ли я использовать эти методы или нет?
Решение
Да , действительно, supr()
не задокументировано.Я с нетерпением ждал возможности использовать его в ExtJS 3.0.0 (сотрудник Ext ответил на форумах, что они добавили его в эту версию), но он кажется ужасно сломанным.
В настоящее время он не пересекает иерархию наследования, а скорее поднимается на один уровень выше, затем застревает на этом уровне, бесконечно зацикливается и взрывает стек (IIRC).Итак, если у вас есть два или более supr()
через несколько секунд ваше приложение выйдет из строя.Я не нашел никакой полезной информации по supr()
ни в документах, ни на форумах.
Я не знаю о версиях обслуживания 3.0.x, поскольку я не получал лицензию службы поддержки...
Другие советы
Я думаю, что это решается в ExtJS 4 с помощью callParent.
Ext.define('My.own.A', {
constructor: function(test) {
alert(test);
}
});
Ext.define('My.own.B', {
extend: 'My.own.A',
constructor: function(test) {
alert(test);
this.callParent([test + 1]);
}
});
Вот шаблон, который я использую, и уже некоторое время собирался написать о нем в блоге.
Ext.ns('MyApp.MyPanel');
MyApp.MyPanel = (function(){
var $this = Ext.extend(Ext.Panel, {
constructor: function() {
// Using a 'public static' value from $this
// (a reference to the constructor)
// and calling a 'private static' method
this.thing = $this.STATIC_PROP + privateStatic();
// Call super using $super that is defined after
// the call to Ext.extend
$super.constructor.apply(this, arguments);
},
initComponent: function() {
$super.initComponent.call(this);
this.addEvents([Events.SOMETHING]); // missing docs here
}
});
var $super = $this.superclass;
// This method can only be accessed from the class
// and has no access to 'this'
function privateStatic() {
return "Whatever";
}
/**
* This is a private non-static member
* It must be called like getThing.call(this);
*/
function getThing() {
return this.thing;
}
// You can create public static properties like this
// refer to Events directly from the inside
// but from the outside somebody could also use it as
// MyApp.MyPanel.Events.SOMETHING
var Events = $this.Events = {
SOMETHING: 'something'
}
return $this;
})();
MyApp.MyPanel.STATIC_STRING = 10;
//Later somewhere
var panel = new MyApp.Mypanel();
panel.on(MyApp.Mypanel.Events.SOMETHING, callback);
Есть много функций, которые вы получаете, используя этот шаблон, но вам не обязательно использовать их все
Вы могли бы использовать эту малоизвестную функцию Javascript (аргументы.вызываемый абонент):
MyApp.MyPanel = Ext.extend(Ext.Panel, {
constructor: function() {
// Do your thing
this.thing = 1;
// Call super
arguments.callee.superclass.constructor.apply(this, arguments);
}
});
видишь Документация MDC
Редактировать:На самом деле, это не будет работать с initComponent, потому что это не конструктор.Лично я всегда переопределяю конструктор (несмотря на то, что предлагают Ext JS examples).Продолжу немного думать об этом.
Я бы просто изменил ваш код на:
var $cls = MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
$cls.superclass.initComponent.call(this);
}
});
Таким образом, вы сохраняете только одну ссылку на имя вашего класса, теперь $cls.Используйте только $cls в методах вашего класса, и все будет в порядке.
Я придумал это решение пару часов назад, хе-хе...
function extend (parentObj, childObj) {
parentObj = parentObj || function () {};
var newObj = function () {
if (typeof this.initialize == 'function') {
this.initialize.apply(this, arguments);
}
}
newObj.prototype.__proto__ = parentObj.prototype;
for (var property in childObj) {
newObj.prototype[property] = childObj[property];
}
newObj.prototype.superclass = function (method) {
var callerMethod = arguments.callee.caller,
currentProto = this.constructor.prototype.__proto__;
while (callerMethod == currentProto[method]) {
currentProto = currentProto.__proto__;
}
return currentProto[method];
};
return newObj;
}
Тогда вы можете сделать:
var A = function () {
this.name = "A Function!";
};
A.prototype.initialize = function () {
alert(this.name);
}
var B = extend(A, {
initialize: function () {
this.name = "B Function!";
this.superclass('initialize').apply(this);
}
});
var C = extend(B, {
initialize: function () {
this.superclass('initialize').apply(this);
}
});
Тестировался только с (Chromium 8.0.552.237 (70801) Ubuntu 10.10) и (Firefox 3.6.13).
Надеюсь, это кому-нибудь поможет, я уже почти переключился на GWT.