先週 3/6 に
Sencha Touch 2.0 がリリースされました。パフォーマンスの向上と、ネイティブアプリ変換が大きく謳われています。
Inkpod Web でも Sencha Touch を使用しています。現在使用しているのが 1.1 のため、早速バージョンアップしてみたいところですが、内部構造が大きく変わってしまい、すぐには対応は難しそうです。
1.x から 2.x へのマイグレーション方法について、以下に記載があります。
Upgrading from Sencha Touch 1.x to 2.x
コンポーネントが全体的に刷新されましたが、その基幹となるクラスシステムと、データモデルについてシンタックスから大きな変更がありました。
ここでは、そのクラスシステムについて概要をお伝えしたいと思います。
How to use classes in Sencha Touch 2 をベースに要点をまとめます。
クラスの基本について
Sencha Touch 2 では、Ext JS4 で開発されたクラスシステムを使うようになりました。
これは、継承、依存関係のロード、ミックスイン、強力な設定オプションなどを提供する JavaScript のクラスを簡単に作ることが出来ます。
次に簡単な例を示します。このアニマルクラスは 名前のプロパティとspeakメソッドを持ちます。
Ext.define('Animal', {
config: {
name: null
},
constructor: function(config) {
this.initConfig(config);
},
speak: function() {
alert('grunt');
}
});
インスタンスを作成するには、Ext.create を使います。
var bob = Ext.create('Animal', {
name: 'Bob'
});
bob.speak(); //alerts 'grunt'
create の第1引数にクラス名、第2引数に設定オプションを渡します。ここでは、Animalクラスに、name が Bob の初期値をセットしています。
2 での変更点
以前は、クラスを作成するには Ext.extend で Object を継承していましたが、 Ext.defined でクラスを定義するようになりました。また、インスタンス生成には new を使用していましたが、Ext.create でクラス名を指定します。1で用意されていたほとんどクラスで設定オプションは使えましたが、自分が作成したクラスでは自分で実装する必要があったものが、自動で有効になったようです。
次に、このクラスを継承して、Humanクラスを作成します。
Ext.define('Human', {
extend: 'Animal',
speak: function() {
alert(this.getName());
}
});
speakメソッドを上書きして、自分の名前を言うようにしました。
Bob を Human にしてみましょう。
var bob = Ext.create('Human', {
name: 'Bob'
});
bob.speak(); //alerts 'Bob'
Humanクラスを定義するときに、getName というメソッドを使用しましたが、これは定義していません。どこから来たのでしょう。クラスに config オプションを定義すると、次のことが自動的に付与されます。
- 現在値を返す getterメソッド。ここでは getName()
- 新しい値をセットする setter メソッド。ここでは getName()
- 設定値が変更されたときに、setter から呼ばれる applierメソッド。 ここでは applyName()
getter、setter メソッドは自動的に生成されます。クラスにデータアクセスする場合、この方法を推奨します。Sencha Touch の全てのクラスはこの形式に沿っているため、config オプションが分かれば、値を get/set することができます。
次に、applier の例です。もし、本当に名前を変更したいか、ユーザに毎回聞きたいとします。このとき、applyNameメソッドを定義すれば、自動的にそれが呼ばれます。
Ext.define('Human', {
extend: 'Animal',
applyName: function(newName, oldName) {
return confirm('Are you sure you want to change name to ' + newName + '?')? newName : oldName;
}
});
ブラウザ組み込みのconfirm関数は確認ダイアログを表示し、YESかNOかユーザに問い合わせます。もし false が返るなら applierメソッドは名前の変更をキャンセルします。
新しいBobを作り名前を変更するときに、プロンプトでNo をクリックします。彼の名前は変更されません。
//訳注: 原文は Person とありますが、typo と思われます
var bob = Ext.create('Human', {
name: 'Bob'
});
bob.setName('Fred'); //確認ダイアログを開き、Noをクリックする
bob.speak(); //まだ 'Bob' のまま
まとめ
- 全てのクラスは Ext.define で定義される。
- extend シンタックスを使用してほとんどのクラスは他のクラスを継承しています。
- インスタンスは Ext.create で生成されます。例: Ext.create('SomeClass', {some: 'configuration'});
- config シンタックスを使うと getter/setter が自動生成されるため、コードベースをきれいに保てます。
2 での変更点
継承方法が、Ext.extend から extend というシンタックスに変更されました。
また、以前には無い機能として configオプションの getter/setter と applier ができました。プロパティアクセスよりも、こちらを使用することが推奨されるようです。(個人的には、プロパティアクセスのほうが便利ですが、typoが検知しやすいというメリットはありますね。)
依存関係と動的ローディング
時々、クラスの中で別のクラスを使うことがあります。ページ内にそれらのクラスがあることを保証するために、requiresシンタックスを使用します。
Ext.define('Human', {
extend: 'Animal',
requires: 'Ext.MessageBox',
speak: function() {
Ext.Msg.alert(this.getName(), "Speaks...");
}
});
この方法でクラスを作成すると、Sencha Touch は、Ext.MessageBox が既にロードされているかチェックします。もし無ければ、AJAXを使用して必要なクラスをロードします。
Ext.MessageBox 自身が依存しているクラスも含めてバックグラウンドで自動的にロードされます。Humanクラスが定義された時に一度だけ全てのクラスがロードされ、Ext.create を使ってインスタンスを作成できるようになります。これは、全てのスクリプトのローディングを自分で管理しなくて良いため、開発時に便利です。しかし、プロダクション環境ではお勧めしません。ファイルを1つずつインターネットからロードすることは遅いからです。
プロダクション環境では、アプリケーションで実際に使用しているクラスだけを含んだ、一つのJavaScript ファイルをロードするのが理想です。JSBuilder Tool をを使えば簡単です。これはあなたのコードを解析し、あなたのクラスと実際に使用しているフレームワークのクラスを一つのファイルにまとめます。詳しくは
Building guide を参照してください。
命名規則
1. クラス
クラス名は アルファベットと数字のみです。数字も、テクニカルターム以外は推奨されません。アンダースコア、ハイフンなどの記号も使ってはいけません。次に例を示します。
- 悪い例: MyCompany.useful_util.Debug_Toolbar
- 良い例: MyCompany.util.Base64
クラス名はパッケージでまとめます。ドット(.)で繋いだオブジェクトプロパティを使います。最低限、一つのユニークなトップレベルネームスペースが必要です。
- MyCompany.data.CoolProxy
- MyCompany.Application
トップレベルネームスペースと、実際のクラス名はキャメルケース(単語の頭を大文字)にし、それ以外は全て小文字にします。
- MyCompany.form.action.AutoLoad
Sencha が提供するクラス以外は Ext をトップレベルに使用しないで下さい。
頭文字の単語もキャメルケースを使用します。
- Ext.data.JsonProxy (Ext.data.JSONProxy ではなく)
- MyCompany.util.HtmlParser (MyCompary.parser.HTMLParser ではなく)
- MyCompany.server.Http (MyCompany.server.HTTP ではなく)
2. ソースファイル
クラス名をそのままファイルパスにします。結果、1クラスは1ファイルになります。
- Ext.mixin.Observable は、 path/to/src/Ext/mixin/Observable.js
- Ext.form.action.Submit は、 path/to/src/Ext/form/action/Submit.js
- MyCompany.chart.axis.Numeric は、 path/to/src/MyCompany/chart/axis/Numeric.js
3. メソッドと変数
クラスメイトほぼ同じです。アルファベットと数字のみで、数字が許されるのはテクニカルタームだけです。メソッドと変数名は常にキャメルケースです。頭文字も同様です。
4. プロパティ
クラスのプロパティ名も定数以外はメソッドと変数と同様です。定数のような静的クラスプロパティは全て大文字にします。
- Ext.MessageBox.YES = "Yes"
- Ext.MessageBox.NO = "No"
- MyCompany.alien.Math.PI = "4.13"
2 での変更点
今まで特に制約は無かった気がしますが、Extパッケージのファイルは大体これにそっていて変更は無いように思います。今回の動的ローディングや JSBuilder の関係で、より命名規則が大事になったのかもしれません。
原文は、まだ「Working with classes in Sencha Touch 2.0」と続きますが、ひとまずここまで。続きは次の機会で。