ホームページ > 記事 > ウェブフロントエンド > Backbone.js 0.9.2 ソースコード解説 中国語翻訳版_基礎知識
// バックボーン.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas、DocumentCloud Inc. // バックボーンは MIT ライセンスに基づいて自由に配布できます。 // すべての詳細とドキュメントについては: // http://backbonejs.org (関数() { // グローバル オブジェクトを作成します。ブラウザではウィンドウ オブジェクトとして表され、Node.js ではグローバル オブジェクトとして表されます。 var root = これ; // 「Backbone」変数の値が上書きされる前に保存します。 // 名前の競合がある場合、または仕様を考慮している場合は、Backbone.noConflict() メソッドを使用して、Backbone によって占有される前の変数の値を復元し、名前変更のために Backbone オブジェクトを返すことができます。 varPreviousBackbone = root.Backbone; // Array.prototype のスライス メソッドとスプライス メソッドを呼び出し用のローカル変数にキャッシュします var スライス = Array.prototype.slice; var splice = Array.prototype.splice; var バックボーン; if( typeof エクスポート !== '未定義') { バックボーン = 輸出。 } それ以外 { バックボーン = root.バックボーン = {}; } //バックボーンのバージョンを定義 バックボーン.VERSION = '0.9.2'; // サーバー環境に Underscore を自動的にインポートします。Backbone の一部のメソッドは Underscore に依存するか、Underscore から継承します。 var _ = root._; if(!_ && ( typeof require !== '未定義')) _ = require('アンダースコア'); // サードパーティ ライブラリを統一変数 "$" として定義します。これは、表示 (View)、イベント処理、およびサーバー データとの同期 (sync) 中にライブラリ内のメソッドを呼び出すために使用されます。 // サポートされているライブラリには jQuery、Zepto などが含まれます。これらは同じ構文を持ちますが、Zepto は主に Webkit コア ブラウザーを対象としています。 // Backbone で使用するために、jQuery に似た構文を使用してカスタム ライブラリをカスタマイズすることもできます (jQuery や Zepto よりも軽いカスタマイズされたバージョンが必要になる場合があります) // ここで定義された「$」はローカル変数であるため、Backbone フレームワーク外のサードパーティ ライブラリの通常の使用には影響しません。 var $ = root.jQuery || root.Zepto || root.ender; // サードパーティのライブラリを手動でセットアップする // Backbone をインポートする前にサードパーティのライブラリをインポートしていない場合は、setDomLibrary メソッドを通じて "$" ローカル変数を設定できます // setDomLibrary メソッドは、Backbone にカスタム ライブラリを動的にインポートするためにもよく使用されます。 Backbone.setDomLibrary = function(lib) { $ = ライブラリ; }; //「Backbone」の後のフレームワークの名前付けを放棄し、Backbone オブジェクトを返します。通常、名前の競合を回避したり、名前付け方法を標準化するために使用されます。 // 例えば: // var bk = Backbone.noConflict(); // 「Backbone」の命名をキャンセルし、Backbone オブジェクトを bk 変数に格納します // console.log(Backbone); // この変数は Backbone オブジェクトにアクセスできなくなり、Backbone が定義される前の値に復元されます。 // var MyBackbone = bk; // bk は Backbone オブジェクトを保存します。名前を MyBackbone に変更します。 Backbone.noConflict = function() { root.Backbone = 前のバックボーン; これを返します。 }; // REST をサポートしていないブラウザの場合は、Backbone.emulateHTTP = true を設定できます。 // サーバー リクエストは POST モードで送信され、オペレーション名を識別するために _method パラメーターがデータに追加され、X-HTTP-Method-Override ヘッダー情報も送信されます。 Backbone.emulateHTTP = false; // application/json エンコードをサポートしていないブラウザの場合は、Backbone.emulateJSON = true に設定できます。 // リクエスト タイプを application/x-www-form-urlencoded に設定し、互換性を確保するためにデータをモデル パラメータに配置します Backbone.emulateJSON = false; // カスタム イベントに関連する Backbone.Events // ------------------ //eventSplitter は、複数のイベントを処理するときのイベント名の解析ルールを指定します。 vareventSplitter = /s /; // カスタム イベント マネージャー // オブジェクト内のイベント関連メソッドをバインドすることで、オブジェクトへのカスタム イベントの追加、削除、トリガーが可能になります。 var イベント = バックボーン.イベント = { // カスタム イベントとコールバック関数を現在のオブジェクトにバインドします // コールバック関数内のコンテキスト オブジェクトは、指定されたコンテキストです。コンテキストが設定されていない場合、コンテキスト オブジェクトはデフォルトで現在バインドされているイベントのオブジェクトになります。 // このメソッドは、DOM Level2 の addEventListener メソッドに似ています。 // events では、空白文字 (スペース、タブなど) で区切って複数のイベント名を指定できます。 // イベント名が「all」の場合、トリガーメソッドの呼び出しによってイベントがトリガーされると、「all」イベントにバインドされているすべてのコールバック関数が呼び出されます。 on : function(イベント、コールバック、コンテキスト) { //一部の関数で使用されるローカル変数を定義します var 呼び出し、イベント、ノード、テール、リスト。 //コールバック関数を設定する必要があります if(!コールバック) これを返します。 //eventSplitter を通じてイベント名を解析し、split を使用して複数のイベント名を配列に分割します // 複数のイベント名を指定するには、通常は空白文字を使用します events = events.split(eventSplitter); // 現在のオブジェクトにバインドされているイベントとコールバック関数のリストを記録する呼び出し 呼び出し = this._callbacks || (this._callbacks = {}); // イベント名のリストをループし、最初から最後までイベント名をイベント変数に保存します。 while( イベント = events.shift()) { // イベントイベントにバインドされたコールバック関数を取得します // list には、単一のイベント名にバインドされたコールバック関数のリストが格納されます。 // 関数リストは配列に格納されませんが、複数のオブジェクトの次の属性を通じて順次関連付けられます。 /**データ格式のような: * { * 末尾: {オブジェクト}、 * 次: { * コールバック: {関数}、 * コンテキスト: {オブジェクト}、 * 次: { * コールバック: {関数}、 * コンテキスト: {オブジェクト}、 * 次へ: {オブジェクト} * } * } * }*/ // リストの各レベルの次のオブジェクトには、コールバック イベント (関数本体、コンテキスト、次のコールバック イベント) に関連する情報が格納されます。 // イベント リストの最上位には末尾オブジェクトが格納され、最後にバインドされたコールバック イベントの識別子 (最後のコールバック イベントの次のオブジェクトと同じオブジェクト) が格納されます。 // テール識別子を通じて、コールバック リストを走査するときに最後のコールバック関数に到達したことがわかります リスト = 呼び出し[イベント]; // ノード変数は、このコールバック関数に関連する情報を記録するために使用されます。 //tail は最後にバインドされたコールバック関数の識別子のみを保存します // したがって、コールバック関数が以前にバインドされている場合は、前のテールをオブジェクトとしてノードに割り当ててから、テールの新しいオブジェクト識別子を作成します // このコールバック イベントが前のコールバックの末尾オブジェクトに追加される理由は、コールバック関数リストのオブジェクト階層をバインド順に配置するためです (最新のバインドされたイベントが最後に配置されます) ノード = リスト ? list.tail : {}; ノード.ネクスト = テール = {}; //このコールバックの関数本体とコンテキスト情報を記録します ノード.コンテキスト = コンテキスト; ノード.コールバック = コールバック; // 現在のイベントのコールバック リストを再構築します。このコールバック イベントはリストに追加されています 呼び出し[イベント] = { 尾: 尾、 次: リスト list.next: ノード }; } // メソッドチェーンの呼び出しを容易にするために現在のオブジェクトを返します これを返します。 }、 // オブジェクト内のバインドされたイベントまたはコールバック関数を削除します。イベント、コールバック、およびコンテキストを通じて、削除する必要があるイベントまたはコールバック関数をフィルターできます。 // - コンテキストが空の場合、コールバックで指定されたすべての関数を削除します // - コールバックが空の場合、イベント内のすべてのコールバック関数を削除します // - イベントが空で、コールバックまたはコンテキストが指定されている場合、コールバックまたはコンテキストで指定されたコールバック関数を削除します (イベント名は区別されません) // - パラメータが渡されない場合は、オブジェクトにバインドされているすべてのイベントとコールバック関数を削除します オフ: 関数(イベント、コールバック、コンテキスト) { var イベント、コール、ノード、テール、cb、ctx; // イベントがない、または *すべて* のイベントを削除します。 // 現在のオブジェクトにはイベントがバインドされていません if(!( call = this._callbacks)) 戻る; // パラメーターが指定されていない場合は、すべてのイベントとコールバック関数を削除します (_callbacks 属性を削除します)。 if(!(イベント || コールバック || コンテキスト)) { this._callbacks を削除します。 これを返します。 } // 削除する必要があるイベント リストを解析します // - イベントが指定されている場合、イベント名はeventSplitterに従って解析されます。 // - イベントが指定されていない場合は、バインドされたすべてのイベントの名前リストを解析します イベント = イベント ? events.split(eventSplitter) : _.keys(calls); // ループイベント名リスト while( イベント = events.shift()) { // 現在のイベント オブジェクトをリストから削除し、ノード変数にキャッシュします。 ノード = 呼び出し[イベント]; 通話を削除[イベント]; // 現在のイベント オブジェクトが存在しない場合 (または削除フィルター条件が指定されていない場合、現在のイベントとすべてのコールバック関数が削除されるとみなされます)、この操作を終了します (イベント オブジェクトは前のステップで削除されています) ) if(!ノード || !(コールバック || コンテキスト)) 続く; // 指定されたコールバックを省略して、新しいリストを作成します。 // コールバック関数またはコンテキストフィルターの条件に従って、新しいイベントオブジェクトをアセンブルし、再バインドします テール = ノード.テール; // イベント内のすべてのコールバック オブジェクトを走査します while(( ノード = ノード.ネクスト) !== テール) { cb = ノード.コールバック; ctx = ノード.コンテキスト; // パラメーター内のコールバック関数とコンテキストに基づいて、コールバック関数をフィルターし、フィルター条件を満たさないコールバック関数をイベントに再バインドします (イベント内のすべてのコールバック関数が上記で削除されているため) if((コールバック && cb !== コールバック) || (コンテキスト && ctx !== コンテキスト)) { this.on(イベント、cb、ctx); } } } これを返します。 }、 // 定義されている 1 つ以上のイベントをトリガーし、バインドされたコールバック関数リストを順番に実行します。 トリガー : 関数(イベント) { var イベント、ノード、呼び出し、末尾、引数、すべて、残り。 // 現在のオブジェクトにはイベントがバインドされていません if(!( call = this._callbacks)) これを返します。 // コールバック関数リストにバインドされている「すべて」のイベント リストを取得します すべて = 呼び出し.すべて; // EventSplitter ルールに従って、配列にトリガーする必要があるイベント名を解析します。 events = events.split(eventSplitter); // トリガーのパラメーターを 2 番目から REST 変数に記録し、順番にコールバック関数に渡します。 残り = スライス.コール(引数, 1); // トリガーする必要があるイベントのリストをループします while( イベント = events.shift()) { // ここのノード変数は、現在のイベントのすべてのコールバック関数のリストを記録します。 if( ノード = 呼び出し[イベント]) { //tail 変数は、最後のバインディング イベントのオブジェクト ID を記録します。 テール = ノード.テール; //ノード変数の値は、イベントのバインド順序に従って、バインドされた単一のコールバック イベント オブジェクトに順番に割り当てられます。 // 最後にバインドされたイベントの next プロパティは、tail と同じオブジェクトを参照します。これは、リストの最後に到達したかどうかを判断するための基準として使用されます。 while(( ノード = ノード.ネクスト) !== テール) { // すべてのバインドされたイベントを実行し、トリガーをコールバック関数に呼び出すときにパラメーターを渡します node.callback.apply(node.context || this,rest); } } // 変数 all はバインド中の「all」イベントを記録します。つまり、イベントが呼び出されると、「all」イベント内のコールバック関数が実行されます。 // - 「all」イベント内のコールバック関数は、バインド順序に関係なく、現在のイベントのすべてのコールバック関数リストが実行された後に順次実行されます。 // - 通常のイベントがトリガーされると、「all」イベントが自動的に呼び出されます。「all」イベントが強制的にトリガーされると、イベント内のコールバック関数が 2 回実行されます。 if(ノード=すべて) { テール = ノード.テール; //通常のイベントのコールバック関数の呼び出しとの違いは、all イベントは現在呼び出されたイベント名を最初のパラメーターとしてコールバック関数に渡すことです。 args = [イベント].concat(rest); // 「all」イベント内のコールバック関数リストをトラバースして実行します while(( ノード = ノード.ネクスト) !== テール) { node.callback.apply(node.context || this, args); } } } これを返します。 } }; // バックボーンの以前のバージョンとの互換性のための、バインディング イベントとリリース イベントのエイリアス イベント.バインド = イベント.on; イベント.アンバインド = イベント.オフ; // Backbone.Model データ オブジェクト モデル //--------------- // Model は Backbone のすべてのデータ オブジェクト モデルの基本クラスであり、データ モデルの作成に使用されます // @param {Object} 属性はモデル作成時の初期化データを指定します // @param {オブジェクト} オプション /*** @format オプション * { * 解析: {ブール値}、 * コレクション: {コレクション} * }*/ var Model = Backbone.Model = function(属性, オプション) { // デフォルト変数はモデルのデフォルト データを保存するために使用されます var のデフォルト。 // 属性パラメータが指定されていない場合は、属性を空のオブジェクトに設定します 属性 || ( 属性 = {}); // 属性のデフォルト データの解析方法を設定します。たとえば、デフォルト データは、設定されたメソッドで必要なデータ形式と互換性があるように、サーバーから取得されます。メソッドを解析に使用できます。 if(オプション && オプション.parse) 属性 = this.parse(属性); if( デフォルト = getValue(this, 'デフォルト')) { // モデルの定義時にデフォルト データを設定する場合、初期化データはデフォルトと属性パラメータとマージされたデータを使用します (属性のデータはデフォルトの同じ名前のデータを上書きします) 属性 = _.extend({}, デフォルト, 属性); } // モデルが属する Collection オブジェクトを明示的に指定します (Collection の add、push などのメソッドを呼び出してモデルをコレクションに追加すると、モデルが属する Collection オブジェクトが自動的に設定されます) if(オプション && オプション.コレクション) this.collection = オプション.コレクション; //attributes 属性には、現在のモデルの JSON オブジェクト化データが格納され、モデル作成時のデフォルトでは空です。 this.attributes = {}; // エスケープ メソッドを通じて処理されたデータをキャッシュする _escapedAttributes キャッシュ オブジェクトを定義します。 this._escapedAttributes = {}; // 各モデルに一意の識別子を設定します this.cid = _.uniqueId('c'); //データのステータスを記録するために使用される一連のオブジェクトを定義します。具体的な意味については、オブジェクトを定義する際のコメントを参照してください。 this.changed = {}; this._silent = {}; this._pending = {}; // インスタンスの作成時に初期化データを設定します。初めてサイレント パラメーターを使用すると、変更イベントはトリガーされません。 this.set(属性, { サイレント : true }); // 初期化データは上で設定されています。変更されたオブジェクト、_silent、_pending オブジェクトのステータスが変更されている可能性があります。ここで再初期化します。 this.changed = {}; this._silent = {}; this._pending = {}; // _previousAttributes 変数にはモデル データのコピーが保存されます // 変更イベントでモデルデータが変更される前の状態を取得するために使用されます。以前の状態のデータは、previous メソッドまたはpreviousAttributes メソッドを通じて取得できます。 this._previousAttributes = _.clone(this.attributes); //initialize初期化メソッドを呼び出す this.initialize.apply(this, 引数); }; // extend メソッドを使用して、Model プロトタイプの一連のプロパティとメソッドを定義します。 _.extend(Model.prototype, イベント, { //変更された属性は、set メソッドが呼び出されるたびに、変更されたデータのキー コレクションを記録します。 変更されました: null、 // // サイレント属性が指定されている場合、変更イベントはトリガーされず、次の変更イベントがトリガーされるまで変更されたデータが記録されます。 // _silent 属性は、サイレントの使用時に変更されたデータを記録するために使用されます _silent : null、 _pending : null、 // 各モデルの一意の識別属性 (デフォルトは「id」、id 属性名は idAttribute を変更することでカスタマイズできます) // データの設定時に id 属性が含まれている場合、その ID はモデルの ID をオーバーライドします。 // ID は、コレクション内のモデルを検索して識別するために使用されます。バックエンド インターフェイスと通信する場合、ID はレコードの識別子としても使用されます。 id属性: 'id', // モデル初期化メソッド。モデルの構築後に自動的に呼び出されます。 初期化: function() { }、 // 現在のモデルのデータのコピーを返します (JSON オブジェクト形式) toJSON : 関数(オプション) { return _.clone(this.attributes); }、 // attr 属性名に従って、モデル内のデータ値を取得します get : function(attr) { this.attributes[attr] を返します。 }、 //attr 属性名に従って、データ値に含まれる HTML 特殊文字が & < を含む HTML エンティティに変換されます。 // _.escape メソッドを通じて実装 エスケープ : 関数(属性) { varhtml; // _escapedAttributes キャッシュ オブジェクトからデータを検索し、データがキャッシュされている場合は直接返します。 if(html = this._escapedAttributes[attr]) HTMLを返します。 // _escapedAttributes キャッシュ オブジェクトにデータが見つかりません // 次に、最初にモデルからデータを取得します var val = this.get(attr); // _.escape メソッドを使用してデータ内の HTML をエンティティに変換し、次回簡単に取得できるように _escapedAttributes オブジェクトにキャッシュします。 return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' val); }、 // 特定の属性がモデルに存在するかどうかを確認します。属性の値をブール型に変換した場合、その値が false の場合、その属性は存在しないものとみなされます。 // 値が false、null、未定義、0、NaN、または空の文字列の場合は、false に変換されます あります: function(attr) { this.get(attr) を返します != null; }、 //モデルにデータを設定します。キー値が存在しない場合は、新しい属性としてモデルに追加されます。キー値が既に存在する場合は、新しい値に変更されます。 set : function(キー、値、オプション) { // attrs 変数に設定する必要があるデータ オブジェクトを記録します var attrs、attr、val; // パラメーター形式では、キーと値のオブジェクト形式、またはキーと値のパラメーターによる個別の設定が可能です。 // key がオブジェクトの場合、オブジェクト形式で設定されているとみなされ、2 番目のパラメータはオプション パラメータとみなされます。 if(_.isObject(key) || key == null) { attrs = キー; オプション = 値; } それ以外 { // keyとvalueの2つのパラメータを別々に設定し、データをattrsオブジェクトに入れて統一処理します。 attrs = {}; attrs[キー] = 値; } // オプション設定項目はオブジェクトである必要があります。オプションが設定されていない場合、デフォルト値は空のオブジェクトです。 オプション || ( オプション = {}); // パラメータが設定されていない場合、アクションは実行されません。 if(!attrs) これを返します。 // 設定されるデータ オブジェクトが Model クラスのインスタンスに属している場合、Model オブジェクトの属性データ オブジェクトを attrs に割り当てます // 通常、このアクションは、ある Model オブジェクトから別の Model オブジェクトにデータをコピーするときに実行されます。 if(モデルの属性インスタンス) attrs = attrs.attributes; // unset 属性がオプション構成オブジェクトに設定されている場合は、attrs データ オブジェクトのすべての属性を未定義にリセットします // 通常、この操作は、ある Model オブジェクトから別の Model オブジェクトにデータをコピーするときに実行されますが、値をコピーせずに、Model 内のデータのみをコピーする必要があります。 if(オプション.unset) for(attr 内の attr) attrs[attr] = ボイド0; //現在のデータを検証し、検証が失敗した場合は実行を停止します if(!this._validate(attrs, options)) false を返します。 // 設定したid属性名がデータコレクションに含まれている場合、そのidをモデルのid属性に上書きする // これは、id 属性名をカスタマイズした後、モデルの id 属性にアクセスするときに id に正しくアクセスできるようにするためです。 if(attrs 内の this.idAttribute) this.id = attrs[this.idAttribute]; var 変更 = options.changes = {}; // 現在のモデルにデータ オブジェクトを記録します var now = this.attributes; // エスケープすると、現在のモデルでエスケープによってキャッシュされたデータが記録されます var エスケープ = this._escapedAttributes; // prev はモデル内のデータが変更される前の値を記録します var prev = this._previousAttributes || {}; // 設定する必要があるデータ オブジェクトを走査します for(attr の attrs) { // attr は現在の属性名を格納し、val は現在の属性値を格納します val = attrs[attr]; // 現在のデータがモデルに存在しない、変更されている、またはオプションで未設定の属性削除が指定されている場合は、_escapedAttributes のデータに置き換えられたデータを削除します。 if(!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) { // エスケープによってキャッシュされたデータのみを削除します。これは、キャッシュ内のデータがモデル内の実際のデータと確実に同期されるようにするためです。 エスケープされた[属性]を削除します。 // サイレント属性が指定されている場合、変更イベントはこの set メソッド呼び出しによってトリガーされないため、変更されたデータは _silent 属性に記録され、次回変更イベントがトリガーされたときにイベント リスニング関数が実行されます。データが変更されたことを通知しました。 // サイレント属性が指定されていない場合は、changes 属性の現在のデータを変更済み状態に直接設定します。 (options.silent ? this._silent : 変更)[attr] = true; } // オプションで unset が設定されている場合は、モデルからデータ (キーを含む) を削除します // unset 属性が指定されていない場合は、新しいデータまたは変更されたデータが追加されるとみなされ、新しいデータがモデルのデータ オブジェクトに追加されます。 オプション。設定を解除しますか? 今[attr]を削除:今[attr] = val; // モデル内のデータが新しいデータと一致しない場合、それはデータが変更されたことを意味します if(!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) { // 現在の属性の変更されたステータスを変更された属性に記録します this.changed[attr] = val; if(!options.silent) this._pending[attr] = true; } それ以外 { // データが変更されていない場合は、変更された属性から変更されたステータスを削除します this.changed[attr] を削除します。 this._pending[attr] を削除します。 } } // 変更メソッドを呼び出します。これにより、変更イベントにバインドされた関数がトリガーされます。 if(!options.silent) this.change(オプション); これを返します。 }、 //指定されたデータを現在のモデルから削除します(属性も同時に削除されます) unset : function(attr, options) { (オプション || ( オプション = {})).unset = true; // options.unset 設定項目を通じて削除操作を実行するように set メソッドに通知します。 return this.set(attr, null, options); }、 // 現在のモデル内のすべてのデータと属性をクリアします クリア : 関数(オプション) { (オプション || ( オプション = {})).unset = true; // 現在のモデルのプロパティのコピーを複製し、options.unset 構成項目を通じて削除操作を実行するように set メソッドに指示します。 return this.set(_.clone(this.attributes), options); }、 // サーバーからデフォルトのモデル データを取得します。データを取得した後、set メソッドを使用してデータをモデルに入力します。そのため、取得したデータが現在のモデルのデータと一致しない場合、変更イベントがトリガーされます。 。 フェッチ : 関数(オプション) { // options が新しいオブジェクトであることを確認してから、options のプロパティを変更します オプション = オプション ? _.clone(オプション) : {}; var モデル = これ; // オプションで、データが正常に取得された後のカスタム コールバック関数を指定できます。 var success = options.success; // データが正常に取得されたら、データを入力し、カスタム成功コールバック関数を呼び出します。 options.success = function(resp, status, xhr) { // サーバーから返されたデータを parse メソッドを通じて変換します // set メソッドを通じて変換されたデータをモデルに入力し、変更イベントがトリガーされるようにします (データが変更されたときに) // データ入力時に検証が失敗した場合、カスタム成功コールバック関数は呼び出されません if(!model.set(model.parse(resp, xhr), options)) false を返します。 // カスタム成功コールバック関数を呼び出す if(成功) 成功(モデル、それぞれ); }; // リクエストでエラーが発生した場合、wrapError を通じてエラー イベントを処理します。 options.error = Backbone.wrapError(options.error, モデル, オプション); // sync メソッドを呼び出してサーバーからデータを取得します return (this.sync || Backbone.sync).call(this, 'read', this, options); }、 //モデル内のデータをサーバーに保存します 保存 : 関数(キー、値、オプション) { // attrs には、サーバーに保存する必要があるデータ オブジェクトが格納されます var 属性、現在の; // 単一の属性 key: value の設定をサポートします // オブジェクト形式での一括設定メソッドをサポート {key:value} if(_.isObject(key) || key == null) { // キーがオブジェクトの場合、オブジェクト メソッドを通じて設定されたものとみなされます // この時点では 2 番目のパラメータはオプションとみなされます attrs = キー; オプション = 値; }それ以外 { // 単一の属性が key:value の形式で設定されている場合は、attrs を直接設定します attrs = {}; attrs[キー] = 値; } // 設定オブジェクトは新しいオブジェクトである必要があります オプション = オプション ? _.clone(オプション) : {}; // options に wait オプションが設定されている場合、変更されたデータを事前に検証し、サーバーが新しいデータに応答しない (または応答に失敗した) 場合、ローカル データを変更前の状態に戻します。 // wait オプションが設定されていない場合、サーバーの設定が成功したかどうかに関係なく、ローカル データは最新の状態に変更されます。 if(オプション.wait) { // 保存が必要なデータを事前に確認する if(!this._validate(attrs, options)) false を返します。 //現在のモデルにデータを記録し、サーバーにデータを送信した後にデータを復元するために使用します // サーバーの応答が失敗した場合、またはデータが返されなかった場合は、変更前の状態を維持できます 現在 = _.clone(this.attributes); } //silentOptions はオプション オブジェクトにサイレントを追加します (データ検証なし) // データは上で検証されているため、wait パラメーターを使用する場合は、silentOptions 構成項目を使用します。 // wait パラメータが設定されていない場合は、元のオプション設定項目が引き続き使用されます var SilentOptions = _.extend({}, オプション, { サイレント : true }); // 同期メソッドでモデル データを取得し、サーバーに保存できるように、最新の変更データをモデルに保存します。 if(attrs && !this.set(attrs, options.wait ?silentOptions : options)) { false を返します。 } var モデル = これ; // オプションでは、データが正常に保存された後にカスタム コールバック関数を指定できます。 var success = options.success; //サーバーが正常に応答した後、成功を実行します options.success = function(resp, status, xhr) { // サーバーの応答の最新のステータス データを取得します var serverAttrs = model.parse(resp, xhr); // wait パラメーターが使用される場合、変更されたデータのステータスが最初にモデルに直接設定されます。 if(オプション.wait) { options.wait を削除します。 serverAttrs = _.extend(attrs || {},serverAttrs); } //最新のデータステータスをモデルに設定する // set メソッドの呼び出し時に検証が失敗した場合、カスタム成功コールバック関数は呼び出されません。 if(!model.set(serverAttrs, options)) false を返します。 if(成功) { // 応答が成功した後に、カスタマイズされた成功コールバック関数を呼び出します。 成功(モデル、それぞれ); } それ以外 { // カスタム コールバックが指定されていない場合、デフォルトで同期イベントがトリガーされます model.trigger('sync', モデル, resp, options); } }; // リクエストでエラーが発生した場合、wrapError を通じてエラー イベントを処理します。 options.error = Backbone.wrapError(options.error, モデル, オプション); //モデル内のデータをサーバーに保存します // 現在のモデルが新しく作成されたモデル (ID なし) の場合は、create メソッド (new) を使用します。それ以外の場合は、update メソッド (modified) とみなされます。 var メソッド = this.isNew() '作成' : '更新'; var xhr = (this.sync || Backbone.sync).call(this, メソッド, this, オプション); // options.wait が設定されている場合は、データを変更前の状態に戻します // 保存されたリクエストは現時点では応答を受信していないため、応答が失敗した場合、モデルは変更前の状態のままになります。サーバーが正常に応答すると、モデル内のデータは成功時の最新の状態に設定されます。 。 if(オプション.待機) this.set(現在、silentOptions); xhr を返します。 }、 //モデルを削除すると、モデルはそれが属するコレクションから削除されます。 // モデルがクライアント上で作成された場合は、クライアントから直接削除します。 // サーバー上にモデルデータが同時に存在する場合、サーバー側のデータも同時に削除されます。 破壊 : 関数(オプション) { // 構成アイテムは新しいオブジェクトである必要があります オプション = オプション ? _.clone(オプション) : {}; var モデル = これ; // オプションで、データが正常に削除された後のカスタム コールバック関数を指定できます。 var success = options.success; // データを削除するために正常に呼び出されると、destroy イベントがトリガーされます。モデルがコレクション内に存在する場合、コレクションは destroy イベントをリッスンし、トリガーされるとコレクションからモデルを削除します。 // モデルを削除すると、モデル内のデータは消去されませんが、モデルはコレクションから削除されるため、モデルへの参照がどこにもない場合、モデルは自動的にメモリから解放されます。 // モデルを削除するときは、モデル オブジェクトの参照変数を null に設定することをお勧めします。 vartriggerDestroy = function() { model.trigger('destroy', モデル, model.collection, options); }; // モデルがクライアントによって新しく作成されたモデルの場合は、triggerDestroy を直接呼び出してコレクションからモデルを削除します。 if(this.isNew()) { トリガー破壊(); false を返します。 }// サーバーからのデータ削除に成功した場合 options.success = function(resp) { // オプション オブジェクトで待機項目が設定されている場合、サーバー データの削除に成功した後、ローカル メモリ内のモデル データが削除されることを意味します。 // サーバーの応答が失敗した場合、ローカル データは削除されません if(オプション.待機) トリガー破壊(); if(成功) { // カスタム成功コールバック関数を呼び出す 成功(モデル、それぞれ); } それ以外 { // カスタム コールバックがない場合、デフォルトで同期イベントがトリガーされます model.trigger('sync', モデル, resp, options); } }; // リクエストでエラーが発生した場合、wrapError を通じてエラー イベントを処理します。 options.error = Backbone.wrapError(options.error, モデル, オプション); //同期メソッドを通じてデータ削除リクエストを送信します var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options); // 待機項目がオプション オブジェクトで設定されていない場合は、最初にローカル データが削除され、次にサーバー データを削除するリクエストが送信されます。 // この時点で、サーバーの削除が成功したかどうかに関わらず、ローカルのモデルデータは削除されています。 if(!options.wait) トリガー破壊(); xhr を返します。 }、 // サーバー インターフェイスでモデルに対応する URL を取得します。save、fetch、destroy などのメソッドを呼び出してサーバーと対話する場合、このメソッドは URL を取得するために使用されます。 // 生成された URL は「PATHINFO」モードに似ています。サーバーにはモデル操作用の URL が 1 つだけあり、簡単に識別できるようにモデル ID が URL に追加されます。 // urlRoot がモデルで定義されている場合、サーバー インターフェイスは [urlRoot/id] の形式である必要があります // モデルが属するコレクションで URL メソッドまたは属性が定義されている場合は、コレクション内の URL 形式を使用します: [collection.url/id] // サーバー URL にアクセスすると、サーバーがレコードを識別しやすくするためにモデル ID が URL に追加されるため、モデル内の ID はサーバー レコードに対応する必要があります。 // モデルまたはコレクションの URL を取得できない場合は、urlError メソッドが呼び出され、例外がスローされます。 // サーバー インターフェイスが「PATHINFO」に従って構成されていない場合は、url メソッドをオーバーロードすることでサーバーとのシームレスな対話を実現できます。 URL : 関数() { //サーバーに対応するURLパスを定義 varbase = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError(); // 現在のモデルがクライアントによって新規に作成されたモデルの場合、id 属性はなく、サーバー URL は直接 Base を使用します。 if(this.isNew()) リターンベース。 // 現在のモデルに id 属性がある場合、save または destroy メソッドを呼び出すことができ、モデルの ID がベースに追加されます。 //以下は、base の最後の文字が "/" であり、生成される URL 形式が [base/id] であるかどうかを判断します。 returnbase (base.charAt(base.length - 1) == '/' ? '' : '/') encodeURIComponent(this.id); }、 // parse メソッドは、サーバーから取得したデータを解析し、set メソッドで解析できるモデル データを返すために使用されます。 // 通常、parse メソッドは、サーバーとのシームレスな接続を構築するために、サーバーから返されたデータに基づいてオーバーロードされます。 // サーバーから返されたデータ構造が set メソッドで必要なデータ構造と一致しない場合 (たとえば、サーバーが XML 形式のデータを返した場合)、parse メソッドを使用して変換できます。 解析 : function(resp, xhr) { 応答を返します。 }、 // 現在のモデルと同じデータを使用して新しいモデルを作成します クローン : function() { 新しい this.constructor(this.attributes) を返します。 }、 // 現在のモデルがクライアントによって作成された新しいモデルかどうかを確認します // チェック方法は、モデルに ID 識別子があるかどうかに基づいています。クライアントによって作成された新しいモデルには ID 識別子がありません。 // したがって、サーバーから応答されるモデル データには id 識別子が含まれている必要があります。識別子の属性名はデフォルトで「id」になります。idAttribute 属性を変更して識別子をカスタマイズすることもできます。 isNew : function() { this.id == null を返します。 }、 // データ更新時に変更イベントバインディングをトリガーする関数 // set メソッドを呼び出すと、change メソッドが自動的に呼び出されます。set メソッドを呼び出すときにサイレント構成が指定されている場合は、change メソッドを手動で呼び出す必要があります。 変更 : 関数(オプション) { // オプションはオブジェクトである必要があります オプション || ( オプション = {}); // これに関連するロジックにいくつかの問題があります。_changing // this._changing はメソッドの最後で false に設定されるため、メソッドの上の Changing 変数の値は常に false になります (初回は未定義) // 作成者の本来の意図は、変更メソッドが実行されたかどうかを示すためにこの変数を使用することであるはずですが、このメソッドは実行時に他のスクリプトをブロックするため、ブラウザ側のシングルスレッド スクリプトでは意味がありません。 // 変更すると、最後のスクリプトが実行されていない場合、値は true になります。 var 変更 = this._changing; // フラグの実行を開始します。実行中、値は常に true になります。実行後、this._changing は false に変更されます。 this._changing = true; //今回の変更以外のデータステータスを _pending オブジェクトに追加します for(this._silent の変数属性) this._pending[attr] = true; // 変更オブジェクトには、現在のデータに対して最後に変更イベントが実行されてから変更されたすべてのデータが含まれます。 // 以前にサイレントを使用して変更イベントがトリガーされなかった場合、今回は変更オブジェクトに配置されます。 varchanges = _.extend({}, options.changes, this._silent); //_silent オブジェクトをリセット this._silent = {}; // 変更オブジェクトを走査し、属性ごとに個別の変更イベントをトリガーします。 for(変更時のvar属性) { // Model オブジェクト、属性値、設定項目をパラメーターとしてイベント リスニング関数に渡します this.trigger('change:' attr, this, this.get(attr), options); } //メソッドが実行中の場合は実行を停止する もし(変化する) これを返します。 // 変更イベントをトリガーします。データが変更されると、「change:property」イベントと「change」イベントが順番にトリガーされます。 while(!_.isEmpty(this._pending)) { this._pending = {}; // 変更イベントをトリガーし、モデル インスタンスと構成アイテムをパラメーターとしてリッスン関数に渡します this.trigger('変更', this, オプション); // 変更されたオブジェクト内のデータを走査し、変更されたデータのステータスを変更済みから順番に削除します // この後、hasChangedを呼び出してデータの状態を確認するとfalse(変更されていない)が返されます。 for(this.changed の var attr) { if(this._pending[attr] || this._silent[attr]) 続く; //変更されたデータのステータスを削除します this.changed[attr] を削除します。 } // 変更イベントの実行後、_previousAttributes 属性は現在のモデルの最新のデータ コピーを記録します。 // したがって、データの以前の状態を取得する必要がある場合、通常は、トリガーされた変更イベントのpreviousまたはpreviousAttributesメソッドを通じてのみ取得できます。 this._previousAttributes = _.clone(this.attributes); } //実行完了フラグ this._changing = false; これを返します。 }、 // 最後の変更イベントが実行されてから特定のデータが変更されたかどうかを確認します /*** 通常は、変更イベント内のpreviousまたはpreviousAttributesメソッドと組み合わせて使用されます。たとえば、次のとおりです。 * if(model.hasChanged('attr')) { * var attrPrev = model.previous('attr'); * }*/ hasChanged : function(attr) { if(!arguments.length) return !_.isEmpty(this.changed); return _.has(this.changed, attr); }、 // 現在のモデルのデータ コレクションと、最後のデータで変更されたデータを取得します // (通常、silent 属性を使用する場合、change メソッドは呼び出されないため、データは変更された属性に一時的に保存されます。最後のデータは、previousAttributes メソッドを通じて取得できます) // 差分セットが渡された場合、最後のモデル データが差分セット内のデータと比較され、一貫性のないデータ セットが返されます。 // 比較結果に差異がない場合は false を返す ChangedAttributes : function(diff) { // diff が指定されていない場合は、以前の状態から変更された現在のモデルのデータ コレクションが返されます。これらのデータは変更された属性に格納されているため、変更されたコレクションのコピーが返されます。 if(!diff) this.hasChanged() を返しますか? _.clone(this.changed) : false; // 比較が必要な差分セットを指定し、最後のデータと差分セットの比較結果を返します。 //古い変数には前の状態のモデルデータが保存されます var val、変更された = false、古い = this._previousAttributes; // diff コレクションを走査し、各項目を以前の状態のコレクションと比較します for(差分の変数属性) { // 比較結果が一致しないデータを変更後の変数に一時的に格納 if(_.isEqual(old[attr], ( val = diff[attr]))) 続く; (変更されました || (変更 = {}))[属性] = val; } // 比較結果を返す 変更された戻り値。 }、 // モデルによってトリガーされる変更イベントで、属性が変更される前の以前の状態のデータを取得します。これは通常、データの比較やロールバックに使用されます。 // このメソッドは通常、変更イベントで呼び出され、変更イベントがトリガーされた後、_previousAttributes 属性に最新のデータが保存されます。 前: function(attr) { // attr は前の状態を取得する必要がある属性名を指定します if(!arguments.length || !this._previousAttributes) null を返します。 this._previousAttributes[attr] を返します。 }、 // モデルが変更イベントをトリガーすると、すべての属性の前の状態のデータ コレクションを取得します // このメソッドは、previous() メソッドに似ています。通常、変更イベントで呼び出され、データの比較またはロールバックに使用されます。 前の属性 : function() { // 以前の状態のデータ オブジェクトを新しいオブジェクトにクローンして返します。 return _.clone(this._previousAttributes); }、 // モデルが現在有効な状態であるかどうかを確認することのみが可能です。 // サイレント変更を使用している場合は *無効* 状態になります。 // 現在のモデルのデータが validate メソッドで検証できるかどうかを確認します。呼び出す前に validate メソッドが定義されていることを確認してください。 isValid : function() { return !this.validate(this.attributes); }、 // データ検証メソッドは、set、save、add などのデータ更新メソッドを呼び出すと自動的に実行されます。 // 検証に失敗すると、モデル オブジェクトの "error" イベントがトリガーされます。 options にエラー処理関数が指定されている場合は、options.error 関数のみが実行されます。 // @param {Object} データ モデルの属性。モデルのオブジェクト化されたデータが格納されます。 // @param {Object} オプション設定項目 // @return {Boolean} 検証に合格した場合は true、失敗した場合は false を返します。 _validate : function(attrs, options) { // set、save、add およびその他のデータ更新メソッドを呼び出すときに options.silent 属性が設定されている場合、検証は無視されます // validate メソッドが Model に追加されていない場合、検証は無視されます if(options.silent || !this.validate) true を返します。 // オブジェクト内のすべての属性値を取得し、検証のために validate メソッドに入れます // validate メソッドには、モデル内のデータ コレクションと構成オブジェクトの 2 つのパラメーターが含まれています。検証に合格した場合、データは返されません (デフォルトは未定義です)。検証が失敗した場合は、エラー情報を含むデータが返されます。 。 attrs = _.extend({}, this.attributes, attrs); var error = this.validate(attrs, options); //検証に合格しました if(!エラー) true を返します。 // 検証に失敗しました // 設定オブジェクトにエラーエラー処理メソッドが設定されている場合は、このメソッドを呼び出し、エラーデータと設定オブジェクトをこのメソッドに渡します if(オプション && オプション.エラー) { options.error(this, エラー, オプション); } それ以外 { // エラー イベント リスナーがモデルにバインドされている場合、バインディング イベントがトリガーされます。 this.trigger('エラー', this, エラー, オプション); } //検証に失敗した識別情報を返す false を返します。 } }); // Backbone.Collection データモデルコレクション関連 //---------------------- // コレクションは同じクラスの一連のデータ モデルを保存し、モデルを操作するための関連メソッドを提供します var Collection = Backbone.Collection = function(モデル、オプション) { //設定オブジェクト オプション || ( オプション = {}); // 構成パラメータにコレクションのモデル クラスを設定します if(オプション.モデル) this.model = オプション.モデル; // comparator 属性が設定されている場合、コレクション内のデータは comparator メソッドの並べ替えアルゴリズムに従って並べ替えられます (add メソッドで自動的に呼び出されます)。 if(オプション.コンパレータ) this.comparator = オプション.comparator; // インスタンス化時にコレクションの内部状態をリセットします (最初の呼び出しは定義状態として理解できます) this._reset(); // 必要に応じて、カスタム初期化メソッドを呼び出します。通常、初期化メソッドはオーバーロードされます。 this.initialize.apply(this, 引数); // モデル データが指定されている場合は、reset メソッドを呼び出してデータをコレクションに追加します。 // サイレントパラメータは初めて呼び出されたときに設定されるため、「reset」イベントはトリガーされません。 if(モデル) this.reset(モデル, { サイレント : 本当、 解析 : options.parse }); }; // extend メソッドを通じてコレクション クラスのプロトタイプ メソッドを定義します _.extend(Collection.prototype, イベント, { // コレクションのモデル クラスを定義します。モデル クラスは Backbone.Model のサブクラスである必要があります。 // コレクション関連のメソッド (add、create など) を使用する場合、データ オブジェクトを渡すことができます。コレクション メソッドは、定義されたモデル クラスに従って、対応するインスタンスを自動的に作成します。 // コレクションに格納されるデータ モデルはすべて同じモデル クラスのインスタンスである必要があります モデル : モデル、 // 初期化メソッド。このメソッドはコレクション インスタンスの作成後に自動的に呼び出されます。 // このメソッドは通常、コレクション クラスを定義するときにオーバーロードされます。 初期化: function() { }、 // コレクション内の各モデルのデータ オブジェクトを含む配列を返します。 toJSON : 関数(オプション) { // Undersocre の map メソッドを使用して、コレクション内の各モデルの toJSON 結果の配列を形成し、返します return this.map(関数(モデル) { // 各モデル オブジェクトの toJSON メソッドを順番に呼び出します。このメソッドはデフォルトでモデルのデータ オブジェクト (コピーされたコピー) を返します。 // 文字列または他の形式を返す必要がある場合は、toJSON メソッドをオーバーロードできます 戻りモデル.toJSON(オプション); }); }、 // 1 つ以上のモデル オブジェクトをコレクションに追加します // 「追加」イベントはデフォルトでトリガーされます。サイレント属性がオプションで設定されている場合、このイベントのトリガーをオフにすることができます。 // 渡されるモデルは 1 つまたは一連のモデル オブジェクト (Model クラスのインスタンス) であり、モデル属性がコレクションに設定されている場合、データ オブジェクト ({name: 'test'} など) が許可されます。データ オブジェクトをモデルが指すモデル オブジェクトに自動的にインスタンス化します。 追加 : 関数(モデル、オプション) { //ローカル変数定義 var i、インデックス、長さ、モデル、cid、id、cids = {}、ids = {}、dups = []; オプション || ( オプション = {}); // モデルは配列である必要があります。モデルが 1 つだけ渡された場合は、それを配列に変換します モデル = _.isArray(モデル) ? モデル.スライス() : [モデル]; // 追加する必要があるモデルのリストを走査します。走査プロセス中に、次の操作が実行されます。 // - データ オブジェクトをモデル オブジェクトに変換する // - モデルとコレクション間の参照を確立します // - 無効なモデルと重複したモデルをログに記録し、後でフィルタリングします for( i = 0, length = models.length; i