Lepszy sposób wywołania metody superclass w ExtJS

Cała dokumentacja i przykłady ExtJS, które przeczytałem, sugerują wywołanie metod klasy superclass w następujący sposób:

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

Używam tego wzorca od dłuższego czasu i głównym problemem jest to, że kiedy zmienisz nazwę swojej klasy, musisz również zmienić wszystkie wywołania na metody superclass. To dość niewygodne, często zapominam, a potem muszę wytropić dziwne błędy.

Ale czytając Źródło Ext.extend() odkryłem, że zamiast tego mogę użyć superclass() lub super() metody, któreExt.extend() dodają do prototypu:

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

W tym kodzie zmiana nazwy MyPanel na coś innego jest prosta - muszę tylko zmienić jedną linię.

Ale mam wątpliwości...
  • Nigdzie nie widziałem tego udokumentowanego, a stara mądrość mówi, że nie powinienem polegać na nieudokumentowanym zachowaniu.

  • Nie znalazłem ani jednego zastosowania tych metod superclass() i supr() w kodzie źródłowym ExtJS. Po co je tworzyć, skoro nie masz zamiaru używać oni?

  • Może te metody były używane w niektórych starszych wersjach ExtJS, ale są teraz przestarzałe? Ale wydaje się to tak przydatna funkcja, dlaczego miałbyś ją dezaktualizować?

Więc, powinienem używać tych metod, czy nie?

Author: blong, 2009-11-12

6 answers

Tak rzeczywiście, supr() nie jest udokumentowane. Nie mogę się doczekać, aby użyć go w ExtJS 3.0.0( członek personelu Ext odpowiedział na forum, dodali go w tej wersji), ale wydaje się strasznie zepsuty.

Obecnie nie przechodzi przez hierarchię dziedziczenia, ale raczej idzie o jeden poziom, a następnie utknie na tym poziomie, pętli bez końca i wysadza stos (IIRC). Tak więc, jeśli masz dwa lub więcej supr() z rzędu, Twoja aplikacja pęknie. Nie znalazłem żadnych przydatnych informacji na supr() w ani dokumentów, ani forów.

Nie wiem co do wersji 3.0.x, ponieważ nie dostałem licencji wsparcia...
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-12 21:05:00

Myślę, że jest to rozwiązane w ExtJS 4 z 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-04 08:22:49

Oto wzór, którego używam i mam zamiar blogować o nim od jakiegoś czasu.

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);

Istnieje wiele funkcji, które można uzyskać za pomocą tego wzoru, ale nie musisz używać wszystkich z nich

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-14 21:13:32

Możesz użyć tej mało znanej funkcji Javascript (argumenty.callee):

MyApp.MyPanel = Ext.extend(Ext.Panel, {
    constructor: function() {
        // Do your thing
        this.thing = 1;

        // Call super
        arguments.callee.superclass.constructor.apply(this, arguments);
    }
});

Patrz dokumentacja MDC

Edit: właściwie, to nie będzie działać z initComponent, ponieważ to nie jest konstruktor. Ja osobiście zawsze nadpisuję konstruktor (pomimo tego co sugerują przykłady Ext JS). Będę się nad tym trochę zastanawiał.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-12 21:02:38

Po prostu zmieniłbym Twój kod na:

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

W ten sposób zachowasz tylko jedno odniesienie do nazwy twojej klasy, teraz $cls. Używaj tylko $cls w swoich metodach klasowych, a wszystko będzie dobrze.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-10 10:13:41

Wymyśliłem to rozwiązanie kilka godzin temu 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;
}

Wtedy możesz zrobić:

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);
    }
});

Testowane tylko z (Chromium 8.0.552.237 (70801) Ubuntu 10.10) oraz (Firefox 3.6.13).

Mam nadzieję, że to komuś pomoże, prawie przerzuciłem się na 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-24 00:32:24