Подтвердить что ты не робот

Лучший способ вызова метода суперкласса в ExtJS

В документации и примерах ExtJS, которые я прочитал, предлагается вызывать методы суперкласса, например:

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

Я использую этот шаблон довольно долгое время, и основная проблема заключается в том, что при переименовании вашего класса вам также необходимо изменить все вызовы на методы суперкласса. Это довольно неудобно, часто я забуду, а затем мне придется отследить странные ошибки.

Но, читая исходный код Ext.extend(), я обнаружил, что вместо этого я мог бы использовать методы 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, но теперь устарели? Но, похоже, такая полезная функция, почему вы ее осуждаете?

Итак, следует ли использовать эти методы или нет?

4b9b3361

Ответ 1

Да, supr() не документирован. Я с нетерпением жду его использования в ExtJS 3.0.0 (член команды Ext ответил на форумах, они добавили его в эту версию), но кажется, что это ужасно нарушено.

В настоящее время он не пересекает иерархию наследования, а поднимается на один уровень, затем застрял на этом уровне, бесконечно петляет и взрывает стек (IIRC). Итак, если у вас есть две или более supr() в строке, ваше приложение будет ломаться. Я не нашел никакой полезной информации о supr() ни в документах, ни в форумах.

Я не знаю о версиях поддержки 3.0.x, так как я не получил лицензию на поддержку...

Ответ 2

Я думаю, что это разрешено в 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]);
    }
});

Ответ 3

Вот шаблон, который я использую, и имел в виду блог об этом некоторое время.

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

Есть много возможностей, которые вы используете с помощью этого шаблона, но вам не обязательно использовать их все

Ответ 4

Вы можете использовать эту малоизвестную функцию 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);
    }
});

см. Документация MDC

Изменить: На самом деле, это не будет работать с initComponent, потому что это не конструктор. Я всегда переопределяю конструктор лично (несмотря на то, что предлагают примеры Ext JS). Будет продолжать думать об этом немного.

Ответ 5

Я бы просто изменил ваш код на:

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

Таким образом, вы сохраняете только одну ссылку своего имени класса, теперь $cls. Используйте только $cls в своих методах класса, и все будет в порядке.

Ответ 6

Я придумал это решение пару часов назад 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;
}

Затем вы можете сделать:

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.