JavaScript MVC学習ノート(六)モデルのORM


MVCと名前空間
アプリケーション中のビュー、状態、データが互いに明瞭に分離されていることを確認してこそ、アーキテクチャがより整然とし、より強固になる.モデルはビューとコントローラから切り離されます.データ操作と挙動に関する論理はすべてモデルに入れ、名前空間によって管理するべきである.
JavaScriptでは、オブジェクトに属性を追加して名前空間を管理します.この名前空間は関数でもあり、変数でもあります.
var User = {
    records: [ /* ... */ ]
};
Userの配列データは、名前空間User.recordsにある.user関連の関数はUserモデルの名前空間にも入れられます.たとえば、fetchRemote()関数を使ってサーバからユーザのデータを取得する.
var User = {
    records: [],
    fetchRemote: function(){ /* ... */ }
};
モデルの属性を名前空間に保存する方法は衝突が発生しないように確保できます.これもMVCの原則に合致しています.コードが関数の山とコールバックが混在する大きなおでんにならないようにします.
名前空間を少し改善して、実際のuserオブジェクトに関する関数も追加できます.userレコードが具体的なuserに関連するdestory()関数を含むと仮定すると、この関数はUserのインスタンスに基づいて呼び出すべきである.
var user = new User;
user.destroy()
このようにするためには、簡単なオブジェクトではなく、Userをクラスに作成する必要があります.
var User = function(atts){
    his.attributes = atts || {};
};

User.prototype.destroy = function(){
    /* ... */
};
具体的なuserと関連しない関数や変数については、Userオブジェクトに直接定義できます.
User.fetchRemote = function(){
    /* ... */
};
オブジェクト関係マップの構築(ORM)
オブジェクト関係マップ(Ojbect-relational mapper、略称ORM)は、JavaScript以外のプログラミング言語でよく見られるデータ構造です.JavaScriptアプリケーションでは、オブジェクト関係マッピングも非常に有用な技術であり、データ管理及びモデル作成に利用できます.例えば、ORMを使用して、モデルとリモートサービスを一緒に縛り上げることができ、いずれのモデル例の変更も、バックグラウンドでAjax要求をサーバ端に開始する.またはモデルのインスタンスとHTML要素を結合して、インスタンスの変更はいずれもインターフェースに反映されます.
カスタムORMを作成します.
本質的には、ORMはいくつかのデータを包装した対象層である.以前はORMは抽象的なSQLデータベースによく使われていましたが、ここではORMは抽象的なJavaScriptデータタイプにすぎません.この追加層には、カスタム関数と属性を追加することにより、基礎データの機能を強化するという利点があります.データを追加する合法的な検証、傍受、データの持続化、サーバ側のコールバック処理など、コードの再利用率を増加させます.
原型引継ぎ
ここではObject.create()を使用してORMを構築し、ここではプロトタイプベースの継承を使用して、構造関数およびnewキーワードを使用しない.Object.create()は一つのパラメータすなわちプロトタイプオブジェクトだけで、新しいオブジェクトに戻ります.この新しいオブジェクトのプロトタイプは着信パラメータです.つまり、オブジェクトが一つ入ってきて、このオブジェクトを継承した新しいオブジェクトを返します.
サポートされていないObject.create()のブラウザについては、この関数を容易にシミュレートすることができる.
if (typeof Object.create !== "function")
    Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
Modelオブジェクトを作成します.Modelオブジェクトは新しいモデルとインスタンスを作成するために使用されます.
var Model = {
    inherited: function(){},
    created: function(){},
    prototype: {
        init: function(){}
    },

    create: function(){
        var object = Object.create(this);
        object.parent = this;
        object.prototype = object.fn = Object.create(this.prototype);
        object.created();
        this.inherited(object);
        return object;
    },

    init: function(){
        var instance = Object.create(this.prototype);
        instance.parent = this;
        instance.init.apply(instance, arguments);
        return instance;
    }
};
create関数は新しいオブジェクトを返します.このオブジェクトはModelオブジェクトから引き継ぎ、新しいモデルを作成します.init()関数は新しいオブジェクトを返します.Model.prototypeから継承されています.Modelオブジェクトのような例です.
var Asset = Model.create();
var User = Model.create();
var user = User.init();
ORM属性を追加
現在Modelオブジェクトに属性を追加すると、継承モデルにとってこれらの新規属性はアクセス可能です.
//       
jQuery.extend(Model, {
    find: function(){}
});

//       
jQuery.extend(Model.prototype, {
    init: function(atts) {
        if (atts) this.load(atts);
    },
    load: function(attributes){
        for(var name in attributes)
        this[name] = attributes[name];
    }
});
jQuery.exted()はforサイクルの代わりに手動で属性をコピーするだけのショートカットです.これはロード関数のやり方と同じです.オブジェクトとインスタンスのプロパティは、個々のモデルに広がっています.
assertEqual( typeof Asset.find, "function" );
実際には多くの属性が追加されますので、exted()とinclude()をModelオブジェクトに追加する必要があります.
var Model = {
    /* ……    ……*/
    extend: function(o){
        var extended = o.extended;
        jQuery.extend(this, o);
        if (extended) extended(this);
    },

    include: function(o){
        var included = o.included;
        jQuery.extend(this.prototype, o);
        if (included) included(this);
    }
};

//       
Model.extend({
    find: function(){}
});

//       
Model.include({
    init: function(atts) { /* ... */ },
    load: function(attributes){ /* ... */ }
});
新しいリソースを作成して属性を設定できます.
var asset = Asset.init({name: "foo.png"});
【公開記録学習JS MVCは、どれぐらい続けられるか分かりません.「MVCベースのJavaScript web富応用開発」を主な学習資料としています.】