JavaScriptモジュール式アプローチ

モジュール方式は、かなり一般的な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をモジュール形式で記述してください!

Source: https://habr.com/ru/post/J117069/


All Articles