モジュール型プログラミングは、非常に一般的な Javascript プログラミング モデルです。通常、これによりコードが理解しやすくなりますが、あまり知られていない優れたプラクティスも数多くあります。
基本
Eric Miraglia (YUI の開発者) が 3 年前にモジュラー パターンについて説明したブログを初めて公開して以来、いくつかのモジュラー パターンの簡単な概要から始めましょう。これらのモジュラー モードにすでに精通している場合は、このセクションをスキップして、「詳細モード」から読み始めることができます。
匿名閉鎖
これはすべてを可能にする基本的な構造であり、JavaScript の最大の機能でもあります。匿名関数を作成してすぐに実行します。すべてのコードはこの関数内で実行され、プライベート化を提供するクロージャ内に存在します。これにより、これらのクロージャ内の変数をアプリケーションのライフサイクル全体を通じて利用できるようにするのに十分です。
匿名関数を囲んでいる最も外側のかっこのペアに注目してください。 Javascript の言語特性のため、この括弧のペアは必要です。 JavaScript では、キーワード function で始まるステートメントは常に関数宣言とみなされます。このコードを括弧で囲むと、それが関数式であることがインタープリタに伝えられます。
グローバル変数インポート
JavaScript には暗黙的グローバル変数と呼ばれる機能があります。変数名がどこで使用されているかに関係なく、インタプリタはスコープ チェーンを逆方向にたどって、変数の var 宣言ステートメントを見つけます。 var 宣言が見つからない場合、変数はグローバル変数とみなされます。この変数が代入ステートメントで使用され、その変数が存在しない場合は、グローバル変数が作成されます。これは、匿名クロージャでグローバル変数を使用または作成するのが簡単であることを意味します。残念ながら、人間の目にはどの変数がグローバルであるかを一目で見分けることができないため、コードの保守が非常に困難になります。
幸いなことに、私たちの匿名関数は簡単な回避策を提供します。グローバル変数を引数として匿名関数に渡すだけで、暗黙的なグローバル変数よりもクリーンで高速なコードが得られます。以下に例を示します:
モジュールのエクスポート
グローバル変数を使用するだけでなく、繰り返し使用できるように宣言したい場合もあります。これは、匿名関数の戻り値を介してエクスポートすることで簡単に行うことができます。これを行うと、モジュール パターンの基本的なプロトタイプが完成し、その後に完全な例が続きます:
MODULE というグローバル モジュールを宣言したことに注意してください。このモジュールには、MODULE.moduleMethod というメソッドと MODULE.moduleProperty という変数という 2 つのパブリック プロパティがあります。さらに、匿名関数クロージャを使用してプライベートな組み込み状態を維持します。同時に、必要なグローバル変数を簡単にインポートし、前に学んだようにこのモジュラー パターンを使用することができます。
アドバンスモード
上記のセクションで説明した基礎は多くの状況に十分に対応できるため、このモジュール パターンをさらに開発して、より強力で拡張可能な構造を作成できるようになります。 MODULE モジュールから始めて、これらの高度なモードを 1 つずつ紹介しましょう。
拡大モード
モジュール全体が 1 つのファイルに存在する必要があるのはモジュラー モードの制限です。大規模なプロジェクトに取り組んだことがある人なら、js を複数のファイルに分割することの価値を理解するでしょう。幸いなことに、私たちは増幅モジュールのための優れた実装を持っています。まず、モジュールをインポートし、プロパティを追加して、最後にエクスポートします。これは例です - 元のモジュールからズームインします:
ここでは必須ではありませんが、一貫性を確保するために var キーワードを使用します。このコードが実行されると、モジュールにはすでに MODULE.anotherMethod という新しいパブリック メソッドが追加されます。増幅ファイルは、独自のプライベートな組み込み状態とインポートされたオブジェクトも維持します。
ワイドズームモード
上記の例では、最初に初期化モジュールを実行する必要があり、その後、増幅モジュールを実行することができます。もちろん、これが必ずしも必要でない場合もあります。 Javascript アプリケーションがパフォーマンスを向上させるためにできる最善の方法の 1 つは、スクリプトを非同期に実行することです。柔軟なマルチパート モジュールを作成し、許容的な拡大モードを通じて任意の順序でロードできるようにすることができます。各ファイルは次の構造に従って編成する必要があります:
このパターンでは、var 式が必要です。 MODULE が初期化されていない場合、この import ステートメントによって MODULE が作成されることに注意してください。これは、LABjs のようなツールを使用して、ブロックせずにすべてのモジュール ファイルを並行してロードできることを意味します。
タイトズームモード
ワイド ズーム モードは優れていますが、モジュールにいくつかの制限も課されます。最も重要なことは、モジュールのプロパティを安全にオーバーライドできないことです。また、初期化中に他のファイルのプロパティを使用することはできません (ただし、実行時には使用できます)。タイト増幅モードには一連の負荷が含まれ、プロパティをオーバーライドできます。これは簡単な例です (元のモジュールを拡大しています):
上記の例では MODULE.moduleMethod の実装をオーバーライドしましたが、必要に応じて元のメソッドへの参照を維持できます。
クローン作成と継承
このモードはおそらく最も柔軟性の低いオプションです。コードの見た目はすっきりしますが、柔軟性が犠牲になります。上で書いたように、プロパティがオブジェクトまたは関数の場合、プロパティはコピーされませんが、オブジェクトまたは関数への 2 番目の参照になります。それらの一方を変更すると、もう一方も同時に変更されます (翻訳者注: 基本的には同じであるため)。このオブジェクトの複製の問題は、再帰的な複製プロセスによって解決できますが、関数の複製では解決できない可能性があります。おそらく eval を使用して解決できます。したがって、この記事では完全を期すためにのみこの方法について説明します。
ファイル間のプライベート変数
モジュールを複数のファイルに分割するには大きな制限があります。各ファイルは独自のプライベート変数を保持し、他のファイルのプライベート変数にはアクセスできません。しかし、この問題は解決できます。以下は、ファイル全体でプライベート変数を維持する寛容なモジュールの例です:
すべてのファイルはそれぞれの _private 変数に属性を設定でき、他のファイルからアクセスできることが理解されています。このモジュールがロードされると、アプリケーションは MODULE._seal() を呼び出して、内部 _private への外部呼び出しを防ぐことができます。モジュールを再スケーリングする必要がある場合、いずれかのファイルの内部メソッドは、新しいファイルをロードする前に _unseal() を呼び出し、新しいファイルの実行後に _seal() を再度呼び出すことができます。私は今日仕事でこのパターンを使用していますが、このアプローチは他では見たことがありません。これは非常に便利なパターンだと思うので、このパターン自体について記事を書く価値があります。
サブモジュール
最後の上級モードは、これまでで最も簡単です。サブモジュールの作成に関する優れた例が多数あります。これは通常のモジュールを作成するのと同じです:
これは単純なことのように思えるかもしれませんが、ここで言及する価値があると思います。サブモジュールには、増幅モードや民営化状態など、一般的なモジュールの高度な利点がすべて備わっています。
結論
ほとんどの高度なモードを組み合わせて、より便利なモードを作成できます。複雑なアプリケーションの設計にモジュール パターンを推奨するとしたら、それは緩やかな拡大パターン、プライベート変数、およびサブモジュールの組み合わせになります。
これらのパターンのパフォーマンスの問題については考えたことはありませんが、これをもっと単純な考え方に置き換えたいと思います。モジュール式パターンのパフォーマンスが優れている場合、ダウンロードを最小限に抑えるのに優れています。このスクリプト ファイルをより高速に実行できます。寛大な増幅モードを使用すると、単純なノンブロッキングの並列ダウンロードが可能になり、ダウンロードが高速になります。初期化時間は他の方法よりわずかに遅くなる可能性がありますが、トレードオフの価値はあります。グローバル変数が正しくインポートされている限り、実行時のパフォーマンスに影響はありません。また、サブモジュール内のプライベート変数を使用して参照チェーンを短縮することで、実行速度を高速化することができます。
最後に、サブモジュール自体を親モジュールに動的にロードする例を示します (親モジュールが存在しない場合は親モジュールを作成します)。わかりやすくするために、プライベート変数を削除しました。もちろん、プライベート変数の追加も非常に簡単です。このプログラミング モデルにより、複雑な階層コード ベース全体をサブモジュール経由で並行してロードできます。
この記事では、「JavaScript モジュール型プログラミング」の現在のベスト プラクティスを要約し、それらを実践する方法について説明します。これは入門チュートリアルではありませんが、JavaScript の基本的な構文を少し理解していれば理解できます。