Лучший способ вызова метода суперкласса в ExtJS
вся документация ExtJS и примеры, которые я прочитал, предлагают вызывать методы суперкласса следующим образом:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
MyApp.MyPanel.superclass.initComponent.call(this);
}
});
я использую этот шаблон в течение некоторого времени, и основная проблема заключается в том, что при переименовании класса вам также нужно изменить все вызовы методов суперкласса. Это довольно неудобно, часто я забуду, и тогда мне придется отслеживать странные ошибки.
но чтение источника Ext.extend()
я обнаружил, что вместо этого я мог бы использовать the 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, но теперь устарели? Но это кажется такой полезной функцией, почему вы ее осуждаете?
Итак, должен ли я использовать эти методы или нет?
6 ответов
Да действительно, 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
Edit: на самом деле это не будет работать с initComponent, потому что это не конструктор. Я всегда переопределяю конструктор лично (несмотря на то, что примеры Ext JS предлагают). Будет продолжать думать об этом немного.
Я бы просто изменить свой код:
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.