クラスシステム

本ガイドは、Ext JS 4.x および 5.x でクラスを新規作成し、既存のクラスを継承することが必要な開発者を対象としています。

概要

Ext JS 5は、300以上のクラスを提供します。現在までに、異なる背景を持ち、様々な地域に住む200万人以上の開発者を抱えています。その規模において、以下のような共通コードを提供するという大きな課題に直面しています。

  • 親しみやすく簡単に学ぶことができる
  • 素早く開発でき、容易にデバッグでき、簡単に展開できる
  • 整備され、拡張とメンテナンスが簡単

JavaScript はクラスがないプロトタイプベース言語で、その最も強力な機能は柔軟性です。いかなる問題に対しても、多くの異なるコーディングスタイルとテクニックを使用した複数のソリューションがあります。ところが、予測できないというデメリットがあります。構造が統一されていない場合、JavaScript コードは理解、保守、再利用が難しくなります。

一方、クラスベースプログラミングは、今なお最も人気のあるオブジェクト指向プログラミングのモデルになります。クラスベースの言語は、通常、強力なタイピングやカプセル化、標準的なコーディング規約を必要とします。開発者を大規模な原則に従わせることによって、コードの予測可能性、将来的な拡張性が高まります。ただし、このモデルには JavaScript の動的な機能はありません。

それぞれの手法は一長一短ですが、デメリットを隠しつつ、両方のメリットを維持することができるでしょうか。その答えはイエスです。Ext JS でソリューションを見つけることができます。

命名規則

クラスや名前空間、ファイル名にコードベース全体で一貫した命名規則を使用することで、整理され構造化された読みやすいコードを保つことができます。

クラス

クラス名には、**英数字**のみを含めることができます。数字の利用は可能ですが、技術用語でない限り推奨されません。アンダーラインやハイフンなどの非英数字文字も使用しないでください。例えば、

  • MyCompany.useful_util.Debug_Toolbar は推奨されません
  • MyCompany.util.Base64 は受け入れられます

クラス名は、オブジェクトプロパティ、ドット表記(.)で適切に名前空間化されたパッケージにグループ化する必要があります。クラス名の前には、一意の上位の名前空間が最低でも1つなければなりません。例:

MyCompany.data.CoolProxy
MyCompany.Application

最上位の名前空間と実際のクラス名はキャメルケースにする必要があります。他はすべて小文字にする必要があります。例:

MyCompany.form.action.AutoLoad

Senchaで公開されていないクラスでは、Extを上位の名前空間として使用しないでください。

また頭字語は、上記のようにキャメルケースの規則に従う必要があります。例:

  • Ext.data.JSONProxy の代わりに Ext.data.JsonProxy
  • MyCompary.parser.HTMLParser の代わりに MyCompany.util.HtmlParser
  • MyCompany.server.HTTP の代わりに MyCompany.server.Http

ソースファイル

クラスの名前は、ストアされるファイルのパスに直接マップされます。その結果、ファイルごとに存在できるクラスは1つのみとなります。例:

  • Ext.util.Observablepath/to/src/Ext/util/Observable.jsに格納されます。
  • Ext.form.action.Submitpath/to/src/Ext/form/action/Submit.jsにストアされます
  • MyCompany.chart.axis.Numericpath/to/src/MyCompany/chart/axis/Numeric.jsにストアされます

path/to/srcは、アプリケーションのクラスのディレクトリです。すべてのクラスは、この共通ルートの下に設置される必要があり、最高の開発、保守、導入エクスペリメントのために正しく名前空間化される必要があります。

メソッドと変数

  • クラス名と同様に、メソッド名と変数名には**英数字**文字のみを含めることができます。数字は使用できますが、技術用語でない限り推奨されません。アンダーラインやハイフンなどの非英数字文字も使用しないでください。

  • メソッドと変数名は常にキャメルケース形式でなければなりません。また、これは略語にも適用されます。

  • 受け入れられるメソッド名
    • encodeUsingMd5()
    • getHtml() instead of getHTML()
    • getJSONResponse() の代わりに getJsonResponse()
    • parseXMLContent() の代わりに parseXmlContent()
  • 受け入れられる変数名
    • var isGoodName
    • var base64Encoder
    • var xmlReader
    • var httpServer

プロパティ

  • Class プロパティ名はスタティック定数の場合以外は全く同じ方法に従います。

  • 定数である静的なクラスプロパティはすべて大文字にする必要があります。例:

    • Ext.MessageBox.YES = "Yes"
    • Ext.MessageBox.NO = "No"
    • MyCompany.alien.Math.PI = "4.13"

宣言

古い方法

これまでに Ext JS 4 よりも古い Ext JS のいずれかのバージョンを使ったことがある場合、クラスを作成する Ext.extend には馴染みがあるでしょう。

var MyWindow = Ext.extend(Object, { ... });

この手法は、別のクラスから継承する新しいクラスの簡単な作り方です。ただ、直接継承以外、クラス作成の他の要素に対して使いやすい API はありませんでした。configuration、statics、mixins などは含んでいませんでした。本ガイドでは、これらのアイテムについて後程見ていきます。

別の例を見てみましょう。

My.cool.Window = Ext.extend(Ext.Window, { ... });

この例では、新しいクラスを名前空間化して、Ext.Window から継承します。その場合、2つの懸念点に対処する必要があります。

  1. My.coolは、プロパティとしてWindowを割り当てる前に、オブジェクトとして存在する必要があります。
  2. Ext.Windowは、参照される前に、ページ上に存在/ロードされている必要があります。

最初の項目は、通常Ext.namespace(エイリアスはExt.ns)で解決されます。このメソッドは再帰的にオブジェクト/プロパティツリーを通過し、ない場合はそれらを作成します。これは、Ext.extend の上に追加する必要があります。

Ext.ns('My.cool');
My.cool.Window = Ext.extend(Ext.Window, { ... });

第2の問題は Ext.Window が多くの他のクラスに依存するため解決するのが難しいということです。代わりに、これらの依存関係は他のクラスがあるかどうかによって決まります。そのため、Ext JS 4以前に記述されたアプリケーションは、フレームワークのごく一部だけが必要な場合でも、ext-all.js のフォーム内に全ライブラリを含んでいました。

新しい方法

Ext JS 4では、クラス作成のために知っておくべき単一のメソッドによって、これらの欠点が排除されます。Ext.define。その基本的なシンタックスは次のとおりです。

Ext.define(className, members, onClassCreated);
  • className:クラス名
  • membersは、キーと値のペアでクラスメンバーのコレクションを表すオブジェクトです
  • onClassCreated は、クラスに定義されたすべての依存関係が準備でき、クラス自体が完全に作成された時に呼び出されるオプションの関数コールバックです。クラス作成は非同期なため、このコールバックは多くの状況で役立ちます。この部分については、セクションIVで詳しく説明します。

例:

Ext.define('My.sample.Person', {
    name: 'Unknown',

    constructor: function(name) {
        if (name) {
            this.name = name;
        }
    },

    eat: function(foodType) {
        alert(this.name + " is eating: " + foodType);
    }
});

var aaron = Ext.create('My.sample.Person', 'Aaron');

aaron.eat("Salad"); // alert("Aaron is eating: Salad");

注意:Ext.create() メソッドを使用して My.sample.Human の新しいインスタンスを作成しています。new キーワード(new My.sample.Person())を使用することもできたかもしれません。いずれにせよ、動的ローディングを利用できますので、常にExt.createを使用する習慣を身につけることをお勧めします。動的ローディングの詳細については、はじめにを参照してください。

設定

Ext JS 4に関して、クラスが作成される前の Ext.Class の強力なプリプロセッサによって処理される専用の config プロパティを導入しました。これらの機能が含まれます。

  • Configurationsは他のクラスメンバーから完全にカプセル化されています。
  • メソッドが定義されていない場合、クラスの作成中にすべてのコンフィグプロパティのゲッターメソッドとセッターメソッドが自動的にクラスのプロトタイプに生成されます。
  • applyメソッドはコンフィグプロパティごとに生成されます。自動生成されたsetterメソッドは、applyメソッドを内部で呼び出してから値を設定します。値を設定する前にカスタムロジックで実行させる必要がある場合、コンフィグプロパティの apply メソッドはオーバーライドできます。apply が値を返さない場合、セッターは値を設定しません。

コンフィグを使用する Ext クラスの場合、Ext JS 5 では initConfig() を手動で呼び出す必要がなくなりました。ただし、作成したクラスが Ext.Base を継承する場合、引き続き initConfig() を呼び出す必要があります。

以下に設定例を示します。

Ext.define('My.own.Window', {
   /** @readonly */
   isWindow: true,

   config: {
       title: 'Title Here',

       bottomBar: {
           height: 50,
           resizable: false
       }
   },

   applyTitle: function(title) {
       if (!Ext.isString(title) || title.length === 0) {
           alert('Error: Title must be a valid non-empty string');
       }
       else {
           return title;
       }
   },

   applyBottomBar: function(bottomBar) {
       if (bottomBar) {
           if (!this.bottomBar) {
               return Ext.create('My.own.WindowBottomBar', bottomBar);
           }
           else {
               this.bottomBar.setConfig(bottomBar);
           }
       }
   }
});

/** A child component to complete the example. */
Ext.define('My.own.WindowBottomBar', {
   config: {
       height: undefined,
       resizable: true
   }
});

ここでは使用方法の例です。

var myWindow = Ext.create('My.own.Window', {
    title: 'Hello World',
    bottomBar: {
        height: 60
    }
});

alert(myWindow.getTitle()); // alerts "Hello World"

myWindow.setTitle('Something New');

alert(myWindow.getTitle()); // alerts "Something New"

myWindow.setTitle(null); // alerts "Error: Title must be a valid non-empty string"

myWindow.setBottomBar({ height: 100 });

alert(myWindow.getBottomBar().getHeight()); // alerts 100

スタティック

静的メンバーはstaticsコンフィグを使って定義できます

Ext.define('Computer', {
    statics: {
        instanceCount: 0,
        factory: function(brand) {
            // 'this' in static methods refer to the class itself
            return new this({brand: brand});
        }
    },

    config: {
        brand: null
    }
});

var dellComputer = Computer.factory('Dell');
var appleComputer = Computer.factory('Mac');

alert(appleComputer.getBrand()); // using the auto-generated getter to get the value of a config property. Alerts "Mac"

エラー処理とデバッグ

Ext JS には、デバッグとエラー処理に役立つ便利な機能が含まれています。

  • どんなメソッドの表示名も、Ext.getDisplayName()を使用して取得することができます。これは、クラス名とメソッド名が説明分に含まれているエラーを投げる場合に特に便利です。

    throw new Error('['+ Ext.getDisplayName(arguments.callee) +'] Some message here');
  • WebKitベースのブラウザ(ChromeやSafari)を使用している場合、エラーがExt.define()を使用して定義された特定のクラスの特定のメソッドでスローされたときに、 コールスタック内のメソッドとクラス名を確認する必要があります。これがChromeでどのように見えるかを以下の例で示します。

Last updated