javascript - Mejor forma de llamar al método de superclase en ExtJS
extend extjs3 (6)
Toda la documentación y los ejemplos de ExtJS que he leído sugieren llamar a métodos de superclase como este:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
MyApp.MyPanel.superclass.initComponent.call(this);
}
});
He estado usando este patrón durante bastante tiempo y el principal problema es que cuando cambia el nombre de su clase, también tiene que cambiar todas las llamadas a métodos de superclase. Eso es bastante inconveniente, a menudo lo olvidaré y luego tendré que rastrear errores extraños.
Pero al leer la fuente de Ext.extend()
descubrí que, en su lugar, podría usar los métodos superclass()
o super()
que Ext.extend()
agrega al prototipo:
MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
this.superclass().initComponent.call(this);
}
});
En este código, cambiar el nombre de MyPanel a otra cosa es simple: solo tengo que cambiar la línea.
Pero tengo dudas ...
No he visto esto documentado en ninguna parte y la sabiduría antigua dice: no debería confiar en el comportamiento indocumentado.
No encontré un solo uso de estos métodos de
superclass()
ysupr()
en el código fuente ExtJS. ¿Por qué crearlos cuando no los va a usar?Tal vez estos métodos se utilizaron en alguna versión anterior de ExtJS pero ahora están en desuso. Pero parece una característica tan útil, ¿por qué lo desaprobarías?
Entonces, ¿debería usar estos métodos o no?
Creo que esto se resuelve en ExtJS 4 con 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]);
}
});
Este es un patrón que uso, y he tenido la intención de escribir sobre él durante un tiempo.
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);
Hay muchas funciones que obtiene usando este patrón, pero no tiene que usarlas todas
He encontrado esta solución hace un par de horas, jeje ...
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;
}
Entonces puedes hacer:
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);
}
});
Probado solo con (Chromium 8.0.552.237 (70801) Ubuntu 10.10) y (Firefox 3.6.13).
Espero que esto ayude a alguien, casi estaba cambiando a GWT.
Puede usar esta característica Javascript poco conocida ( 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);
}
});
ver la documentación de MDC
Editar: en realidad, esto no va a funcionar con initComponent porque no es el constructor. Siempre anulo el constructor, personalmente (a pesar de lo que sugieren los ejemplos de Ext JS). Seguirá pensando en esto un poco.
Sí, de hecho, supr()
no está documentado. He estado esperando usarlo en ExtJS 3.0.0 (un miembro del personal Ext respondió en los foros, lo habían agregado en esa versión), pero parece terriblemente roto.
Actualmente no atraviesa la jerarquía de herencia, sino que sube un nivel, luego se atasca en este nivel, se repite sin parar y explota la pila (IIRC). Entonces, si tienes dos o más supr()
seguidas, tu aplicación se romperá. No he encontrado ninguna información útil sobre supr()
ni en los documentos ni en los foros.
No sé sobre las versiones de mantenimiento 3.0.x, ya que no obtuve una licencia de soporte ...
Simplemente cambiaría tu código a:
var $cls = MyApp.MyPanel = Ext.extend(Ext.Panel, {
initComponent: function() {
// do something MyPanel specific here...
$cls.superclass.initComponent.call(this);
}
});
De esta forma solo conservas una sola referencia de tu nombre de clase, ahora $ cls. Solo use $ cls dentro de los métodos de su clase y estará bien.