Mejor manera de llamar al método superclass en ExtJS


Toda la documentación y ejemplos de ExtJS que he leído sugieren llamar a métodos de superclase de esta manera:

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 cambias el nombre de tu clase, también tienes que cambiar todas las llamadas a métodos de superclase. Eso es bastante inconveniente, a menudo lo olvidaré y luego tengo que rastrear errores extraños.

Pero leyendo la fuente de Ext.extend() descubrí, que en su lugar podría usar el superclass() o super() métodos que Ext.extend() añade 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 una línea.

Pero tengo dudas...

  • No he visto esto documentado en ninguna parte y la vieja sabiduría dice, no debería confiar en el comportamiento indocumentado.

  • No encontré un solo uso de estos métodos superclass() y supr() en el código fuente de ExtJS. Por qué crearlos cuando no vas a usarlos ellos?

  • Tal vez estos métodos se utilizaron en alguna versión anterior de ExtJS, pero están en desuso ahora? Pero parece una característica tan útil, ¿por qué lo desaprobaría?

Entonces, ¿debo usar estos métodos o no?

Author: blong, 2009-11-12

6 answers

Sí, de hecho, supr() no está documentado. He estado esperando usarlo en ExtJS 3.0.0 (un miembro del personal de Ext respondió en los foros, lo habían agregado en esa versión), pero parece horriblemente roto.

Actualmente no atraviesa la jerarquía de herencia, sino que sube un nivel, luego se atasca en este nivel, hace bucles interminables y explota la pila (IIRC). Por lo tanto, si tiene dos o más supr() en una fila, su aplicación se romperá. No he encontrado ninguna información útil sobre supr() en ni los documentos ni los foros.

No conozco las versiones de mantenimiento 3.0.x, ya que no obtuve una licencia de soporte...

 13
Author: Jabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-12 21:05:00

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]);
    }
});
 29
Author: tykovec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-04 08:22:49

Aquí hay un patrón que uso, y he estado queriendo bloguear sobre él por 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 características que obtienes usando este patrón, pero no tienes que usarlas todas

 5
Author: Juan Mendes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-14 21:13:32

Podría usar esta característica de Javascript poco conocida (argumentos.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 Documentación MDC

Edit: 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 Ext JS). Continuará pensando en esto un poco.

 3
Author: neonski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-12 21:02:38

Simplemente cambiaría su código a:

var $cls = MyApp.MyPanel = Ext.extend(Ext.Panel, {
  initComponent: function() {
    // do something MyPanel specific here...
    $cls.superclass.initComponent.call(this);
  }
});

De esa manera solo conservas una sola referencia del nombre de tu clase, ahora $cls. Solo use $cls dentro de sus métodos de clase y estará bien.

 2
Author: karlipoppins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 10:13:41

Se me ocurrió esta solución hace un par de horas jejeje...

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.

 0
Author: rseidi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 00:32:24