JavaScriptはプロトタイプベース言語であり、典型的なクラスベース言語とは違います。JavaScriptでは、新しいクラスを生成は、オブジェクトのprototypeを書き換えることにより実現しています。Extはクラスの生成と操作を簡単にするためのメソッド群を用意しています(こちらのページ(英語)ではJavaScriptにおける様々な「継承」手法に関するディスカッションがされていますので興味のある方は参考にしてみてください)。
ExtはJavaScriptクラスを継承(extend)あるいは上書き(override)するためメソッドを用意しています。つまり、既存のクラスに独自の動作を組み込んだ新しいクラスを作ったり、いくつかのメソッドだけを選択して既存の動作を上書きすることもできるということです。
Person = Ext.extend(Object, {
constructor: function(first, last){
this.firstName = first;
this.lastName = last;
}
getName: function(){
return this.firstName + ' ' + this.lastName;
}
});
Developer = Ext.extend(Person, {
getName: function(){
if(this.isCoding){
return 'Go Away!';
}else{
// 親クラスのgeNameメソッドにアクセス
return Developer.superclass.getName.call(this);
}
}
});
var p = new Person('John', 'Smith');
alert(p.getName());
// Personクラスが定義されているものと仮定 Ext.override(Person, { getName: function(){ // 氏・名の順番で名前を返すように動作を上書き return this.lastName + ' ' + this.firstName; } });
prototypeに格納されたアイテムは、そのクラスの全てのインスタンスにおいて共有されます。特に理由が無い限りは、prototypeの中には"primitive"(JavaScriptで定義されているデータ型)のみを格納するようにしてください。
MyClass = Ext.extend(Object, {
// このオブジェクトリテラルはMyClassの全てのインスタンスで共有される
baseParams: {},
foo: function(){
this.baseParams.bar = 'baz';
}
});
Ext.onReady(function(){
var a = new MyClass();
var b = new MyClass();
a.foo();
// 変数aのbaseParamsを変更することにより変数bのbaseParamsも変更される
console.log(b.baseParams);
});
モジュールパターンとも言われるシングルトンパターンでは、クロージャを活用することによりJavaScriptにおいてプライベート変数やメソッドを生成することを可能とします。シングルトンは、静的メソッドを提供するクラスや1度しか利用しないクラスなどをつくる場合に非常に便利なパターンといえます。使いどころとしては、アプリケーションのエントリポイントなどが挙げられます。
MyApp = function(){
var data; 変数dataはプライベート変数となり外部からは直接アクセスできない
return {
init: function(){
// アプリケーションを初期化
},
getData: function(){
return data;
}
};
}();
Ext.onReady(MyApp.init, MyApp);
Observable (あるいは subscriber)パターンは、観察対象のオブジェクトとそのオブジェクトを観察するオブジェクトが存在する場合に、それらのオブジェクトの独立性を保つために利用されるデザインパターンです。オブジェクトの独立性はイベントを利用することにより実現されています。観察対象オブジェクトは、その状態が変化すると該当するイベントを「発火(fire)」します。そのオブジェクトが発火したイベントを観察しているオブジェクト(subscriber)は、対象の状態に変化があったことを知らされ、その情報に基づき何らかの処理を実行することになります。Extクラスの多くはObservableクラスを継承しているため、柔軟でかつ独立性の高いプログラムを設計することが可能となっています。以下のように、独自イベントを発火するクラスを作ることができます:
var MyClass = Ext.extend(Ext.util.Observable, {
constructor: function(config){
this.addEvents('datachanged'); // 発火させるイベントを指定
MyClass.constructor.call(this, config);
},
update: function(){
// 何らかのデータ操作
// イベントを発火する際に、subscriberに渡すパラメーターを指定することができる
this.fireEvent('datachanged', this, this.data.length);
}
});
// イベントを観察
var c = new MyClass();
c.on('datachanged', function(obj, num){
// datachangedイベントに対する処理
});
名前空間は、2つの主な利点をコード管理にもたらしてくれます。1つ目は、グローバル変数を様々なオブジェクトで「汚染」することを防いでくれることです。Extでは「Ext」というたった一つのグローバル変数を追加するだけです。クラスを定義する場合は、常に会社名やアプリケーション名を頂点とする名前空間の下に定義するようにしてください。もう1つの利点は、コード全体を整理することに役立つということです。例えば似たようなクラスや互いに依存する関係にあるようなクラスを同じ名前空間にまとめることにより、他の開発者にとっても分かりやすいコードになります。
// 下記はどちらも同じ意味ですが、通常は後者を使います Ext.namespace( 'MyCompany', 'MyCompany.Application', 'MyCompany.Application.Reports' ); Ext.namespace('MyCompany.Application.Reports');