Melhor maneira de método chamada superclasse em ExtJS
-
19-09-2019 - |
Pergunta
Toda a documentação ExtJS e exemplos eu li sugerem métodos de chamada superclasse como esta:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
MyApp.MyPanel.superclass.initComponent.call(this);
}
});
Eu tenho usado este padrão por algum tempo e que o principal problema é que, quando você renomeia sua classe, em seguida, você também tem que mudar todas as chamadas para os métodos da superclasse. Isso é bastante inconveniente, muitas vezes eu vou esquecer e então eu tenho para rastrear erros estranhos.
Mas lendo a fonte de Ext.extend()
eu descobri, que, em vez eu poderia usar os métodos superclass()
ou super()
que Ext.extend()
acrescenta ao protótipo:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
this.superclass().initComponent.call(this);
}
});
Neste código renomeando myPanel para outra coisa é simples -. Eu só tenho que mudar a uma linha
Mas não tenho dúvidas ...
-
Eu não vi isso documentado em qualquer lugar e a velha sabedoria diz, eu não deveria contar com o comportamento em situação irregular.
-
Eu não encontrei uma única utilização desses métodos
superclass()
esupr()
em código fonte ExtJS. Por que criá-los quando você não está indo para usá-los? -
Talvez esses métodos foram utilizados em alguma versão mais antiga do ExtJS mas estão obsoletos agora? Mas parece uma característica tão útil, por que você iria depreciar-lo?
Então, eu deveria usar esses métodos ou não?
Solução
Sim, de fato, supr()
não é documentado. Eu estive olhando para a frente a usá-lo em ExtJS 3.0.0 (um membro da equipe Ext respondeu nos fóruns, que tinha acrescentado que nessa versão), mas parece terrivelmente quebrado.
Atualmente, não atravessar a hierarquia de herança, mas sim subir um nível, então fica preso a este nível, loops indefinidamente e explode a pilha (IIRC). Então, se você tiver dois ou mais supr()
consecutivo, a sua aplicação vai quebrar. Eu não encontrei qualquer informação útil sobre supr()
em nem os documentos nem os fóruns.
Eu não sei sobre o 3.0.x versões de manutenção, desde que eu não obter uma licença de suporte ...
Outras dicas
Eu acho que isso é resolvido em ExtJS 4 com 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]);
}
});
Aqui está um uso padrão I, e estava querendo blog sobre isso por um tempo.
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);
Há uma série de características que você começa usando este padrão, mas você não tem que usar todos eles
Você pode usar esse pouco conhecido recurso Javascript ( arguments.callee ):
MyApp.MyPanel = Ext.extend(Ext.Panel, {
constructor: function() {
// Do your thing
this.thing = 1;
// Call super
arguments.callee.superclass.constructor.apply(this, arguments);
}
});
Edit: Na verdade, isso não vai trabalhar com initComponent porque não é o construtor. Eu sempre substituir o construtor, pessoalmente (apesar do que exemplos Ext JS sugerir). Vai continuar a pensar em um presente um pouco.
Eu simplesmente alterar seu código para:
var $cls = MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
$cls.superclass.initComponent.call(this);
}
});
Dessa forma, você só manter uma única referência do seu nome da classe, agora $ cls. Só use $ cls dentro de seus métodos de classe e você vai ficar bem.
Eu vim com essa solução um par de horas atrás heheh ...
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;
}
Em seguida, você pode fazer:
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);
}
});
Testado apenas com (Cromo 8.0.552.237 (70801) Ubuntu 10.10) e (Firefox 3.6.13).
Espero que isso ajuda alguém, eu estava quase mudando para GWT.