Лучший способ вызова метода суперкласса в 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.