モジュール方式は、かなり一般的なJavaScriptプログラミング手法です。 通常は十分に理解されていますが、高度な技術については十分に説明されていません。 この記事では、基本を説明し、元々のトリックを含むいくつかの複雑なトリックに触れます。
基本
YUIのEric Miragliaが最初にこれについて書いたのでよく知られている、モジュラーアプローチの簡単な概要から始めます。 モジュラーアプローチに既に慣れている場合は、高度なテクニックに進んでください。
匿名クロージャー
この基本設計は、すべての基礎であり、javascriptで最も優れています。 無名関数を作成し、すぐに実行します。 すべての実行可能コードはクロージャ内に存在し、アプリケーション全体のライフタイムを通じてプライバシーと状態の保持を提供します。
( 関数 ( ) {// ...このコンテキスト内でのみすべての変数と関数//グローバル変数に引き続きアクセスできます} ( ) ) ;無名関数の周りの()に注意してください。 これは言語で必要です。というのは、単語functionで始まるステートメントは常に関数宣言として解釈されるためです。 ()を追加すると、代わりに関数式が作成されます。
グローバル輸入
JavaScriptは、いわゆるデフォルトグローバルをサポートしています。 変数名に一致すると、インタプリタはその名前のvar演算子を探してコンテキストチェーンをたどります。 そうでない場合、変数はグローバルであると想定されます。 割り当てで使用される場合、グローバルなものがまだ作成されていなければ作成されます。 つまり、匿名クロージャーでグローバル変数を使用または作成することは非常に簡単です。 残念ながら、これはコードのメンテナンスが不十分になるため、(人々にとって)このファイルでどの変数がグローバルであるかは明らかではありません
幸いなことに、匿名関数は単純な代替手段を提供します。 グローバルパラメーターをパラメーターとして匿名関数に渡すことにより、それらをコードにインポートします。これは、デフォルトのグローバルパラメーターよりも明確で高速です。 例:
( 関数 ( $
、 YAHOO
) {//これで、コードはjQuery変数($など)およびYAHOOにアクセスできます} ( jQuery
、 YAHOO
) )) ;モジュールのエクスポート
グローバルなものだけでなく、宣言したい場合もあります。 無名関数の戻り値を介してエクスポートすることにより、これを簡単に行うことができます。 このトリックは、基本的なモジュラーアプローチを完了します。完全な例を次に示します。
var MODULE
= ( function ( ) {var my
= { } 、privateVariable
= 1 ;関数 privateMethod
( ) {// ...}私の
moduleProperty = 1 ;私の
moduleMethod = function ( ) {// ...} ;私を
返す ;} ( ) ) ;MODULE.moduleMethodというメソッドとMODULE.modulePropertyという変数という2つのパブリックメンバーを持つMODULEというグローバルモジュールを宣言していることに注意してください。 さらに、匿名関数のクロージャを使用して別の内部状態を保存し、さらに以前のアプローチを使用してグローバル変数を簡単にインポートできます。
高度なアプローチ
多くの場合、上記の手法で十分であるにもかかわらず、それらを改善し、非常に強力で拡張可能な設計を作成できます。 MODULEという名前のモジュールから順番に検討します。
補充
モジュール方式の制限の1つは、モジュール全体を1つのファイルに含める必要があることです。 大規模なプログラムで作業したことがある人なら誰でも、コードを複数のファイルに分割することの重要性を理解しています。 幸いなことに、モジュールを補充するためのエレガントなソリューションがあります。 最初に、モジュールをインポートし、次にメンバーを追加してからエクスポートします。 MODULEモジュールが完成した例を次に示します。
var MODULE
= ( function ( my
) {私の
anotherMethod = function ( ) {//メソッドを追加...} ;私を
返す ;} (モジュール
) ) ;ここでも、均一性のためにvarを使用していますが、これは必須ではありません。 このコードが実行されると、モジュールにはMODULE.anotherMethodという新しいパブリックメソッドが作成されます。 補充ファイルには、独自の状態とインポートされた変数も保存されます。
無料充電
前の例は、事前に作成され、後で補充されるモジュールに依存していましたが、別の方法で行うことができます。 パフォーマンスを改善するためにできる最善のJavaScriptアプリケーションは、スクリプトを非同期にロードすることです。 無料の充電を使用して、任意の順序で自分自身をロードする、柔軟なモジュールを細かく分割できます。 各ファイルには次の構造が必要です。
var MODULE
= ( function ( my
) {//機能を追加...私を
返す ;} (モジュール
|| { } ) ) ;このスキームでは、var演算子が常に必要です。 まだインポートしていない場合、インポートするとモジュールが作成されることに注意してください。 これは、LABjsなどのユーティリティを使用して、ブロックなしですべてのファイルをモジュールと並行してダウンロードできることを意味します。
限られた補充
無料の補充は良いですが、制限を課します。その主なものは、モジュールメンバーを安全にオーバーライドできないことです。 また、初期化の完了中(ただし、完了後)は、他のファイルのモジュールメンバーを使用できません。 限られた補充は起動順序を設定しますが、上書きを許可します。 次に簡単な例を示します(古いモジュールを補充します):
var MODULE
= ( function ( my
) {var old_moduleMethod
= my。
moduleMethod ;私の
moduleMethod = function ( ) {//メソッドをオーバーライドし、old_moduleMethodを介してoldにアクセスします...} ;私を
返す ;} (モジュール
) ) ;ここでは、MODULE.moduleMethodを再定義しましたが、必要に応じて、元のメソッドへの参照を保存しました。
クローニングと継承
var MODULE_TWO
= ( function ( old
) {var my
= { } 、キー
;for (古いキー
) {if ( old。hasOwnProperty ( key
) ) {my
[ key
] = old
[ key
] ;}}var super_moduleMethod
= old。
moduleMethod ;私の
moduleMethod = function ( ) {//クローンのメソッドをオーバーライドし、super_moduleMethodを介してsuperにアクセスします} ;私を
返す ;} (モジュール
) ) ;このアプローチはいくらか優雅さをもたらしますが、柔軟性を犠牲にします。 オブジェクトまたは関数であるメンバーは複製されず、2つの名前を持つ単一のオブジェクトとして存在し続けます。 一方を変更すると、もう一方も変更されます。 オブジェクトの場合、これは再帰的な複製によって修正できますが、関数はevalを除いて役に立たないようです。 どういうわけか、私は完全性のためにこれを含めました。
クロスファイル状態
モジュールをファイルに分割することの重大な制限は、各モジュールが独自の状態を保存し、他のファイルの状態を表示しないことです。 すべての補充にもかかわらず、状態を保存する無料の追加モジュールの例を次に示します。
var MODULE
= ( function ( my
) {var _private
= my._private
= my._private
|| { } 、_seal
= my._seal
= my._seal
|| 関数 ( ) {my._privateを
削除します
。my._sealを
削除します
。my._unsealを
削除します
。} 、_unseal
= my._unseal
= my._unseal
|| 関数 ( ) {my._private
= _private
;my._seal
= _seal
;my._unseal
= _unseal
;} ;// _private、_seal、および_unsealへの永続的なアクセス私を
返す ;} (モジュール
|| { } ) ) ;どのファイルもローカル変数_privateにメンバーを設定でき、外部からすぐにアクセスできます。 このモジュールが完全にロードされると、アプリケーションはMODULE.seal()を呼び出して、内部_privateへの外部アクセスを防ぎます。 アプリケーションの存続期間中にモジュールを補充する場合、内部メソッドの1つは、新しいファイルをロードする前に_unseal()を呼び出し、実行後に_seal()を呼び出すことができます。
今日、職場でそれが起こりました。私はこれを見たことはありませんでした。 これは非常に有用なアプローチであり、個別に説明する価値があると思います。
サブモジュール
最新の高度なアプローチが最も簡単です。 サブモジュールを作成する理由はたくさんあります。 これは、通常のモジュールを作成する方法です。
モジュール
sub = ( function ( ) {var my
= { } ;// ...私を
返す ;} ( ) ) ;それがどれほど明白であっても、言及する価値があるように思えました。 サブモジュールには、補充や状態保存など、通常のモジュールのすべてのプロパティがあります。
結論
最も高度なアプローチを組み合わせることができます。 複雑なアプリケーションを作成するときは、個人的に無料の補充、プライベートステート、およびサブモジュールを選択します。
パフォーマンスの問題にはまったく触れませんでしたが、簡単に言うことができます。モジュール方式は生産的です。 十分に縮小されているため、読み込みが高速化されます。 無料のトップアップにより、ノンブロッキングパラレルロードを使用できるようになり、コードの実行速度も向上します。 初期化時間は他のアプローチよりも長くなる可能性がありますが、それだけの価値はあります。 グローバル変数が正しくインポートされていれば、実行パフォーマンスが低下することはありません。また、ローカルモジュールでの変数チェーンの削減により、サブモジュールではおそらくさらに改善されます。
結論として、その親によって動的にロードされる(必要に応じて作成される)サブモジュールを受け入れます。 簡潔にするために状態の保存をスキップしましたが、追加は簡単です。 このアプローチにより、サブモジュールなどを使用して、複雑な階層コードを完全に並行してロードできます。
var UTIL
= ( function ( parent
、 $
) {var my
= parent。
ajax =親。
アヤックス || { } ;私の
get = function ( url
、 params
、 callback
) {// OK、だから私は少し浮気しています:)$を
返します。
getJSON ( url
、 params
、 callback
) ;} ;//など...親を
返す ;} ( UTIL
|| { } 、 jQuery
) ) ;あなたがそれを楽しんだことを願って、あなたの考えを共有してください。 JavaScriptをモジュール形式で記述してください!