2009-11-12 8 views
28

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

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

+0

На самом деле, вы могли бы попробовать 'this.constructor.superclass.initComponent.call (this);'? – neonski

+0

Спасибо, но это имеет ту же проблему, что описал Джебе - она ​​работает только для одного уровня иерархии. –

ответ

13

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

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

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

+0

Спасибо, это действительно не работает для нескольких уровней иерархии наследования. FYI: в этом отношении ничего не изменилось в 3.0.3. –

+1

В любом случае с Sencha Touch 1.1 – Vitaly

3

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

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

+0

Callee устарел. – Jabe

+3

JavaScript 1.4: Устаревший вызов как свойство функции.аргументов, сохранил его как свойство переменной локальных аргументов функции. Не то же самое! – neonski

+0

А, извините, вы правы. Я смутился с полностью устаревшим «вызывающим». Снятие жалобы было бы довольно беспорядочным. – Jabe

5

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

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

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

+0

Приятно, но этот подход вводит довольно много кода шаблона, который может быть прекрасным, если вы вызываете много методов родительского класса, но мне обычно просто нужно вызвать родителя initComponent() и ничего другого, и в этом случае дополнительный код IMHO не стоит. –

+0

Да, этот шаблон предназначен для всего кода OO, используя наследование, где вы бы назвали методы родителя. В Ext, я часто вызываю onRender, afterRender, beforeDestroy от родителей, так как я его переопределяю. –

+0

Это замечательно, спасибо! Мне это особенно нравится, поскольку он может передать JSLint/[JSHint] (http://jshint.com/), если все сделано правильно. У меня были некоторые проблемы _linting_ [этот формат из старого учебника Sencha] (http://www.sencha.com/learn/legacy/Tutorial:Extending_Ext_for_Newbies#Extending_Functionality). – blong

2

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

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

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

+1

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

0

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

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

Испытано только с (Хром 8.0.552.237 (70801) Ubuntu 10.10) и (Firefox 3.6.13).

Надеюсь, что это поможет кому-то, я почти переключился на GWT.

+1

'Function.caller' и' Object .__ proto__' являются нестандартными. Кроме того, последнее устарело. Хотя, идея выглядит интересной. –

29

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

+1 только то, что я искал :) – jrharshath

+1

Вопрос относится к Ext JS 3.x (для пользователей, которые могут прочитать это позже) – blong