web-dev-qa-db-ja.com

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の名前を別の名前に変更するのは簡単です。1行を変更するだけです。

でも疑問があります...

  • 私はこれがどこにも文書化されているのを見たことがありませんし、古い知恵によれば、私は文書化されていない振る舞いに頼るべきではありません。

  • ExtJSソースコードでこれらのsuperclass()およびsupr()メソッドの単一の使用法は見つかりませんでした。使用しないときに作成するのはなぜですか?

  • これらのメソッドは古いバージョンのExtJSで使用されていたかもしれませんが、現在は非推奨ですか?しかし、それはそのような便利な機能のようです、なぜそれを廃止するのですか?

それで、私はこれらの方法を使うべきですか?

29
Rene Saarsoo

確かに、supr()は文書化されていません。私はこれをExtJS 3.0.0で使用することを楽しみにしています(Extスタッフメンバーがフォーラムで返信しました。彼らはそのバージョンで追加しました)。ひどく壊れているようです。

現在、継承階層を通過せず、1レベル上に移動してから、このレベルでスタックし、無限にループし、スタック(IIRC)を爆破します。したがって、2つ以上のsupr()が連続している場合、アプリは破損します。 supr()に関する有用な情報は、ドキュメントにもフォーラムにも見つかりませんでした。

サポートライセンスを取得していなかったため、メンテナンスリリース3.0.xについてはわかりません...

14
Jabe

これは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]);
    }
});
29
tykovec

これが私が使用するパターンで、しばらくの間それについてブログを書くことを意味していました。

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

このパターンを使用して取得する機能はたくさんありますが、すべてを使用する必要はありません

5
Juan Mendes

このほとんど知られていない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の例が示唆していることにかかわらず)。これについては少し考え続けます。

3
neonski

私は単にあなたのコードを次のように変更します:

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

このようにして、クラス名の単一の参照のみを保持します。現在は$ clsです。クラスメソッド内でのみ$ clsを使用すれば大丈夫です。

2
karlipoppins

私はこのソリューションを数時間前に思いつきました...

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に切り替えていました。

0
rseidi