ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript のモジュール パターン プログラミングの詳細な分析

JavaScript のモジュール パターン プログラミングの詳細な分析

coldplay.xixi
coldplay.xixi転載
2020-07-29 17:32:283006ブラウズ

JavaScript のモジュール パターン プログラミングの詳細な分析

基礎知識

まず、モジュール パターン (YUI の Eric Miraglia による 2007 年) の概要を理解する必要があります。提案されているブログで説明されています)、すでにモジュール モードに精通している場合は、このセクションをスキップして「アドバンス モード」を直接読むことができます。

関連する学習の推奨事項: JavaScript ビデオ チュートリアル

匿名関数クロージャ

匿名関数クロージャ パッケージこれは JavaScript の最大の機能であり、あらゆることが可能になります。次に、匿名関数を作成し、すぐに実行してみましょう。関数内のすべてのコードはクロージャで実行され、クロージャは実行プロセス全体におけるこれらのコードのプライバシーとステータスを決定します。

コードは次のとおりです:

(function () {
 // ... all vars and functions are in this scope only
 // still maintains access to all globals
}());

匿名関数の外側の括弧に注意してください。これは、JavaScript で function で始まるステートメントが一般に関数宣言とみなされているためです。外側の括弧を追加すると、関数式が作成されます。

グローバル インポート

JavaScript には、隠しグローバル変数と呼ばれる機能があります。変数名が使用される場合、コンパイラーは var を使用してステートメントを検索し、変数を宣言します。見つからない場合、変数はグローバルとみなされます。割り当て中にこのように使用すると、グローバル スコープが作成されます。これは、匿名クロージャでグローバル変数を作成するのが非常に簡単であることを意味します。残念ながら、ファイル内でグローバル変数が宣言されていないことがプログラマにとって不明瞭であるため、これによりコードが管理不能になる可能性があります。幸いなことに、匿名関数により、別のオプションが提供されます。匿名関数のパラメーターを使用してグローバル変数をコードにインポートできます。これにより、より高速かつ適切になります。

コードは次のとおりです:

(function ($, YAHOO) {
// now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));

モジュール エクスポート

グローバル変数を使用したくない場合がありますが、使用したい場合があります。それらを宣言すること。匿名関数の戻り値を通じて簡単にエクスポートできます。モジュール パターンの基本的な内容についてはここまでですが、ここではより複雑な例を示します。

コードは次のとおりです。

var MODULE = (function () {
 var my = {},
  privateVariable = 1;
 function privateMethod() {
  // ...
 }
 my.moduleProperty = 1;
 my.moduleMethod = function () {
  // ...
 };
 return my;
}());

ここでは、MODULE というグローバル モジュールを宣言します。このモジュールには、MODULE.moduleMethod というメソッドと MODULE.moduleProperty という変数という 2 つのパブリック プロパティがあります。さらに、匿名関数のクロージャを通じてプライベートな内部状態を維持します。もちろん、前述のモードを使用して、必要なグローバル変数を簡単にインポートすることもできます。

先ほど述べたものは多くのニーズには十分ですが、このパターンをさらに深く掘り下げて、強力でスケーラブルな構造を作成できます。 MODULEというモジュールで少しずつ学習を進めていきましょう。

拡張

現時点では、モジュール モードの制限の 1 つは、モジュール全体を 1 つのファイルに記述する必要があることです。大規模なコード開発を行ったことがある人なら誰でも、1 つのファイルを複数のファイルに分割することの重要性を知っています。幸いなことに、モジュールを拡張する優れた方法があります。まずモジュールをインポートし、次に属性を追加し、最後にそれをエクスポートします。ここでは、上記の方法を使用して MODULE を拡張する例を示します。

コードは次のとおりです:

var MODULE = (function (my) {
 my.anotherMethod = function () {
  // added method...
 };
 return my;
}(MODULE));

不要ですが、一貫性を保つために var キーワードを再度使用します。次にコードが実行され、モジュールによって MODULE.anotherMethod というパブリック メソッドが追加されます。拡張ファイルは、独自のプライベートな内部状態を維持し、インポートします。


緩やかな拡張

上の例では、最初にモジュールを作成してからモジュールを拡張する必要がありますが、これは必須ではありません。スクリプトを非同期的にロードすることは、JavaScript アプリケーションのパフォーマンスを向上させる最良の方法の 1 つです。 。緩やかな拡張を通じて、任意の順序でロードして複数のファイルに分割できる柔軟なモジュールを作成します。各ファイルの構造はおおよそ次のとおりです。

コードは次のとおりです。

var MODULE = (function (my) {
 // add capabilities...
 return my;
}(MODULE || {}));

このモードでは、var ステートメントが必要です。インポートされたモジュールが存在しない場合は作成されます。つまり、LABjs などのツールを使用して、これらのモジュール ファイルを並行して読み込むことができます。


タイトな拡張

緩やかな拡張は優れていますが、モジュールにいくつかの制限が追加されます。最も重要な点は、モジュール属性を安全にオーバーライドする方法がなく、初期化中に他のファイルでモジュール属性を使用できないことです (ただし、初期化後の実行時には使用できます)。コンパクト拡張には特定のロード順序が含まれますが、書き換えがサポートされています。以下に例を示します (オリジナルの MODULE を拡張)。

コードは次のとおりです:

var MODULE = (function (my) {
 var old_moduleMethod = my.moduleMethod;
 my.moduleMethod = function () {
  // method override, has access to old through old_moduleMethod...
 };
 return my;
}(MODULE));

ここでは MODULE.moduleMethod を書き換え、必要に応じて元のメソッドへの参照を保持しています。


コピーと継承

コードは次のとおりです:

var MODULE_TWO = (function (old) {
 var my = {},
  key;
 for (key in old) {
  if (old.hasOwnProperty(key)) {
   my[key] = old[key];
  }
 }
 var super_moduleMethod = old.moduleMethod;
 my.moduleMethod = function () {
  // override method on the clone, access to super through super_moduleMethod
 };
 return my;
}(MODULE));

这种模式可能是最不灵活的选择。虽然它支持了一些优雅的合并,但是代价是牺牲了灵巧性。在我们写的代码中,那些类型是对象或者函数的属性不会被复制,只会以一个对象的两份引用的形式存在。一个改变,另外一个也改变。对于对象来说[g5] ,我们可以通过一个递归的克隆操作来解决,但是对于函数是没有办法的,除了eval。然而,为了完整性我还是包含了它。

跨文件的私有状态

把一个module分成多个文件有一很大的局限,就是每一个文件都在维持自身的私有状态,而且没有办法来获得其他文件的私有状态。这个是可以解决的,下面这个松拓展的例子,可以在不同文件中维持私有状态。

代码如下:

var MODULE = (function (my) {
 var _private = my._private = my._private || {},
  _seal = my._seal = my._seal || function () {
   delete my._private;
   delete my._seal;
   delete my._unseal;
  },
  _unseal = my._unseal = my._unseal || function () {
   my._private = _private;
   my._seal = _seal;
   my._unseal = _unseal;
  };
 // permanent access to _private, _seal, and _unseal
 return my;
}(MODULE || {}));

每一个文件可以为它的私有变量_private设置属性,其他文件可以立即调用。当module加载完毕,程序会调用MODULE._seal(),让外部没有办法接触到内部的 _.private。如果之后module要再次拓展,某一个属性要改变。在载入新文件前,每一个文件都可以调用_.unsea(),,在代码执行之后再调用_.seal。

这个模式在我今天的工作中想到的,我从没有在其他地方见到过。但是我认为这是一个很有用的模式,值得单独写出来。

Sub-modules

最后一个高级模式实际上是最简单的,有很多创建子module的例子,就像创建一般的module一样的。

代码如下:

MODULE.sub = (function () 
{ var my = {}; //
    ...
 return my;}());

虽然这可能是很简单的,但是我决定这值得被写进来。子module有一般的module所有优质的特性,包括拓展和私有状态。

总结

大多数高级模式都可以互相组合来创建更有用的新模式。如果一定要让我提出一个设计复杂应用的方法的话,我会结合松拓展,私有状态,和子module。

在这里我没有提到性能相关的事情,但是我可以说,module模式对于性能的提升有好处。它可以减少代码量,这就使得代码的载入更迅速。松拓展使得并行加载成为可能,这同样提升的载入速度。初始化的时间可能比其他的方法时间长,但是这多花的时间是值得的。只要全局变量被正确导入了运行的时候就不会出问题,在子module中由于对变量的引用链变短了可能也会提升速度。

最后,这是一个子module自身动态加载的例子(如果不存在就创建),为了简介我没有考虑内部状态,但是即便考虑它也很简单。这个模式可以让复杂,多层次的代码并行的加载,包括子module和其他所有的东西。

代码如下:

var UTIL = (function (parent, $) {
 var my = parent.ajax = parent.ajax || {};
 my.get = function (url, params, callback) {
  // ok, so I'm cheating a bit 
  return $.getJSON(url, params, callback);
 };
 // etc...
 return parent;
}(UTIL || {}, jQuery));

我希望这些内容是有用的,请在下面留言来分享你的想法。少年们,努力吧,写出更好的,更模块化的JavaScript。

以上がJavaScript のモジュール パターン プログラミングの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjb51.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。