Лучший способ вызвать метод суперкласса в ExtJS - PullRequest
29 голосов
/ 12 ноября 2009

Вся документация 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, но сейчас устарели? Но это кажется такой полезной функцией, с какой стати вы ее осуждаете?

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

Ответы [ 6 ]

29 голосов
/ 04 мая 2011

Я думаю, что это решается в 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]);
    }
});
14 голосов
/ 13 ноября 2009

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

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

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

5 голосов
/ 28 октября 2010

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

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

Существует множество функций, которые вы получаете, используя этот шаблон, но вам не обязательно использовать все из них

3 голосов
/ 12 ноября 2009

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

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

2 голосов
/ 10 января 2011

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

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

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

0 голосов
/ 24 января 2011

Я придумал это решение пару часов назад, хе-хе ...

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...