ホームページ > ウェブフロントエンド > jsチュートリアル > Javascriptのモジュール化と名前空間管理に関する問題の説明_JavaScriptスキル

Javascriptのモジュール化と名前空間管理に関する問題の説明_JavaScriptスキル

WBOY
リリース: 2016-05-16 18:14:24
オリジナル
1010 人が閲覧しました

【モジュール化とモジュール化が必要な理由】

まず、なぜモジュール化が必要なのかについて話しましょう。実際、これは依然としてコーディングのアイデアとコード管理の利便性に関連しています (名前空間汚染の問題については言及されていません。モジュール化されたアイデアを検討したプログラマーは、少なくとも独自の一連の命名規則を持つべきだと私は信じているからです。中小規模の企業では) -サイズのプロジェクトでは、名前空間の汚染の可能性は非常に小さいですが、それが存在しないという意味ではありません。この問題については後で説明します。
実際、モジュールの考え方は、私たちの口で言ういわゆる「モジュール」がいわゆる「オブジェクト」よりも大きなオブジェクトである可能性があることを除いて、依然としてオブジェクト指向の考え方と同じです。適切なカプセル化によって同じ目的を達成するための関数を組み合わせ、そのような結合されたコードフラグメントのアイデアをオブジェクト指向のアイデアと呼ぶことができます。これを行うことには、使いやすさ、多用途性、保守性、可読性、変数名の汚染の回避など、多くの利点があります。
モジュール化とは、オブジェクト指向とモジュール指向に他なりません。同じプロジェクト(モジュール)に関連する機能パッケージを有機的に結合し、共通の名前で管理します。それは、おおまかにモジュール化されたアイデアであると言えます。したがって、オブジェクト指向と比較すると、実際には、コード アーキテクチャでモジュールのアイデアを実装するのがオブジェクト指向よりも簡単だと思います。
C#、Java、および優れたモジュール性と名前空間メカニズムを備えた他の強く型付けされた言語とは異なります。 JavaScript は、モジュールを作成および管理するための言語機能を提供しません。このため、js コーディングを行うとき、いわゆる名前空間の使用は、(私自身を含めて) 少しカジュアルすぎるように見えます。例:

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

var Honru = {} / / 名前空間

(function(){
Hongru.Class1 = function () {
//TODO
}
...
Hongru.Class2 = function () {
//TODO
}
})();

上記のように、通常、名前空間としてグローバル変数またはグローバル オブジェクトを使用します。これは非常に単純であるため、これにこのような重大な責任を委ねるのは少しカジュアルなようにさえ思えます。しかし、これが悪いと言えるでしょうか?いや、むしろ、このようなコーディングの習慣がある学生は称賛されるべきだと思います。 。 。


したがって、いくつかのプロジェクトを実行したり、小規模な Web サイトを構築したりする場合、実際にはこの方法を使用して名前空間の作業を行うだけで十分であり、基本的に大きな問題は発生しません。しかし、本質に戻りましょう。コードのクリーンさや大規模な Web サイトの構築に夢中になっている場合、または最初から完全にエレガントな態度とロジックでコード構造に取り組んでいる場合です。おそらく、より良い名前空間の登録方法と管理方法を検討する必要があるでしょう。
この点では、jQuery は YUI、Mootool、EXT などと比較すると若干劣りますが (ただし、jq には独自のモジュール機構のセットもあります)、それでも私たちの jQuery への愛を妨げるものではありません。焦点は異なります。jq の強みはセレクターにあり、そうでなければ j-Query とは呼ばれません。
したがって、jQuery が中小規模の Web サイトに適していると言うのは理にかなっています。 Douban のオープンソース フロントエンド軽量フレームワークである Do フレームワークと同様に、これも jQuery 上に構築されており、モジュール管理のアイデアと同期ファイル読み込みの機能のレイヤーをカプセル化しています。

[名前空間について]

さて、本題に戻りましょう。 上記のように、グローバル オブジェクトを使用して名前空間を作成するだけで、グローバル変数を効果的に削減し、変数名汚染の問題を回避できます。 . ただし、Web サイトが大きくなったり、プロジェクトの数が増えたりすると、複数のグローバル オブジェクトの名前空間を管理する際に問題が発生します。偶然名前の競合が発生すると、あるモジュールが別のモジュールのプロパティを上書きし、一方または両方が正しく動作しなくなります。そして、問題が発生した場合、それを特定するのは非常に面倒です。したがって、名前空間を作成するときに重複する名前があるかどうかを判断できるメカニズムまたはツールが必要になる場合があります。

一方で、異なるモジュール、つまり異なる名前空間は完全に独立しているわけではなく、異なる名前空間に同じメソッドまたは属性を作成する必要がある場合もあります。この場合、インポートとエクスポートも行うことができます。問題になる。

上記の2点について、少し考えてテストしてみましたが、まだ間違いがいくつかあります。今日、私は「Rhinoceros Book」をもう一度読みました。それは上記の問題を簡単に解決しました。 「Rhinoceros Book」のソリューションとデモをベースに、いくつかの修正と簡略化を行いました。一般的な理解を共有してください。より重要な点は次のとおりです:

-- 各サブモジュールの使いやすさをテストします

名前空間はオブジェクトであるため、オブジェクトが持つべき階層関係を持っています。検出 このような階層関係に基づいて、名前空間の使用可能性を判断して登録する必要があります。これは、サブ名前空間を登録する場合に特に重要です。たとえば、新しい名前空間を Honru として登録した後、別の名前空間を Honru.me として登録する必要があります。つまり、本来の目的は、me 名前空間が Honru のサブ名前空間であることです。父と子の関係。そのため、名前空間を登録する際には「.」で区切って一つ一つ判断する必要があります。したがって、名前空間を登録するコードはおおよそ次のとおりです。

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

// 名前空間を作成 --> 最上位の名前空間を返す
Module.createNamespace = function (name, version) {
if (!name) throw new Error('name required');
if (name.charAt(0) == '.' || name.charAt(name.length-1) == '.' || name.indexOf('..') != -1) throw new Error(' 不正な名前');

var Parts = name.split('.');

var コンテナ =
for (var i=0; ivar パーツ = パーツ[i];
if (!コンテナ[パーツ]) = {}; 🎜>}

var namespace = コンテナ;
if (namespace.NAME) throw new Error('モジュール "' name '" はすでに定義されています');
namespace.NAME = name; 🎜>if (version) namespace.VERSION = version;

Module.modules[name] = namespace;


;上記のモジュールは、名前空間を登録および管理するための共通モジュールです。「ベース モジュール」として、モジュールのモジュール キュー属性があり、新しく登録された名前空間を格納するために使用されます。このキューにより、名前空間を簡単に決定できます。が登録されました:





コードをコピーします
コードは次のとおりです:

var Module;
//check Module --> 'Module' が存在しないことを確認します
if (!!Module && (typeof Module != 'object' || Module.NAME )) throw new Error("NameSpace 'Module' はすでに存在します!");

Module = {};

Module.NAME = 'Module.VERSION = 0.1 ;

Module.EXPORT = ['require',
'importSymbols'];

Module.EXPORT_OK = ['createNamespace',
'isDefined',
'モジュール',
'globalNamespace'];

Module.globalNamespace = this;

Module.modules = {'Module': モジュール};上記のコードの最後の行は名前空間キューであり、新しく作成された名前空間はすべてそのキューに配置されます。前のコードと組み合わせると、基本的に名前空間を非常に適切に管理できます。「ベース モジュール」モジュールに関しては、後述する EXPORT などの他の属性も備えています。以下は、名前空間を作成するためのテスト デモです




コードをコピーします
コードは次のとおりです: Module.createNamespace('Hongru', 0.1);//Hongru という名前の名前空間、バージョン 0.1 を登録します
必要がなければ、上記の 2 番目のバージョンのパラメーターも省略できますバージョン番号。新しく登録された名前空間は、chrome-debugger
の下に表示されます。

新しく登録された Honru 名前空間が有効になっていることがわかります。 Module のモジュール キューを見てください:

新しく登録された Honru も追加されていることがわかります。モジュールキュー内のモジュール。 Module には require、isDefined、importSymbols などのメソッドがいくつかあることも誰もが発見しました。
これら 2 つのメソッド require (バージョンの検出) と isDefined (名前空間の検出時にすでに登録されている) は難しくないため、もう少し単純です。


-- バージョンと重複名の検出



コードをコピー
コードは次のとおりです。 // 名前が定義されているかどうかを確認します。 Module.isDefined = function (name) {
Module.modules の名前を返します。 🎜>} ;
// バージョンをチェック
Module.require = function (name, version) {
if (!(Module.modules の名前)) throw new Error('モジュール ' 名前 ' が異なります定義済み') ;
if (!version) return;
var n = Module.modules[name];
if (!n.VERSION || n.VERSION

上記の 2 つの方法は、キューが同じ名前かどうかを検出することであることは誰もが理解していると思います。もう 1 つは、バージョンが要件を満たしているかどうかを検出することです。特別なことは何もないので、詳細は説明しません。もう少し複雑なのは、名前空間間の属性またはメソッドの相互インポートです。
--名前空間内のタグの属性またはメソッドのエクスポート
私たちが必要としているのは汎用の名前空間登録および管理ツールであるため、タグをインポートまたはエクスポートするときに構成可能性を考慮する必要があります。これらをすべて一度にインポートまたはエクスポートすることはできません。 。したがって、モジュール テンプレートには 2 つの配列 EXPORT と EXPORT_OK があり、エクスポートが許可されている属性またはメソッドを保存するためのタグ キューとして認識されます。このうち、EXPORT はパブリック タグ キューであり、EXPORT_OK はカスタマイズできるタグ キューです。よくわからない場合は、許可されているタグ属性またはメソッドを格納するために 1 つのタグ キューのみを使用することもできます。輸出。
タグ キューの場合、エクスポート操作は EXPORT タグ キューと EXPORT_OK タグ キュー内のタグのみに対して行われます。



コードをコピー

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

// モジュールをインポートします
Module.importSymbols = function (from) {
if (typeof form == 'string') from = Module.modules[from];
var to = Module.globalNamespace; //デフォルト
var シンボル = [];
var firstsymbol = 1;
if (arguments.length>1 && 引数の種類[1] == 'オブジェクト' && 引数[1] != null) {
to = 引数[1];
最初のシンボル = 2;
}
for (var a=firstsymbol; asymbols.push(arguments[a]);
}
if (symbols.length == 0) {
//デフォルトのエクスポートリスト
if (from.EXPORT) {
for (var i=0; ivar s = from.EXPORT[i];
to[s] = from[s];
}
戻る;
} else if (!from.EXPORT_OK) {
// EXPORT 配列 && EXPORT_OK 配列両方とも未定義
for (var s in from) {
to[s] = from[s];
戻る;
}
}
}
if (symbols.length > 0) {
var allowed;
if (from.EXPORT || form.EXPORT_OK) {
allowed = {};
if (from.EXPORT) {
for (var i=0; iallowed[from.EXPORT[i]] = true;
}
}
if (from.EXPORT_OK) {
for (var i=0; iallowed[form.EXPORT_OK[i] ] = true;
}
}
}
}
// シンボル
をインポートします (var i=0; ivar s = シンボル[私];
if (!(s in from)) throw new Error('シンボル ' s ' が定義されていません');
if (!!allowed && !(s in allowed)) throw new Error(s ' はパブリックではないため、インポートできません');
to[s] = form[s];
}
}

このメソッドの最初のパラメータは出力元空間、2 番目のパラメータは入力対象空間(選択可能、承認は定義されたグローバル名前空間)です。
以下はテストデモです。
複製コード 代码如下:

Module.createNamespace('Hongru');
Module.createNamespace('me', 0.1);
me.EXPORT = ['define']
me.define = function () {
this.NAME = '__me';
}
Module.importSymbols(me, Honru);// ハンドル名字空间下の标记导入到Hongru名字空间下

可看赋试結果:
 

本来の名前定義は mename 空間の下にあるメソッド define() は、Hongruname 空間の下に挿入されます。 もちろん、ここでの入出力はコピーのみであり、mename 空間では define() を使用することができます。

よろしくお願いします。このデモは管理名空間の完全な方法を提供するだけであり、より優れた方法があることを認めています。以下の YUI、EXT などのフレームを参照してください。または、《JavaScript 权威指南》を参照してください。

モジュールと名前空間です。

最終贴下资源:

复制代码代码如下:

/* == モジュールと名前空間ツール機能 ==
* 著者 : hongru.chen
* 日付 : 2010-12-05
*/
var モジュール;
//モジュールをチェック --> 'Module' が存在しないことを確認してください
if (!!Module && (typeof Module != 'object' || Module.NAME)) throw new Error("NameSpace 'Module' selected!");
モジュール = {};
モジュール.NAME = 'モジュール';
モジュール.バージョン = 0.1;
Module.EXPORT = ['require',
'importSymbols'];
Module.EXPORT_OK = ['createNamespace',
'isDefined',
'モジュール',
'globalNamespace'];
Module.globalNamespace = this;
Module.modules = {'モジュール': モジュール};
// 名前空間を作成 -->最上位の名前空間を返します
Module.createNamespace = function (name, version) {
if (!name) throw new Error('name required');
if (name.charAt(0) == '.' || name.charAt(name.length-1) == '.' || name.indexOf('..') != -1) throw new Error('不正な名前');
var Parts = name.split('.');
var コンテナ = Module.globalNamespace;
for (var i=0; ivar part = Parts[i];
if (!コンテナ[パーツ]) コンテナ[パーツ] = {};
コンテナ = コンテナ[パーツ];
}
var 名前空間 = コンテナ;
if (namespace.NAME) throw new Error('モジュール "' name '" は既に定義されています');
namespace.NAME = 名前;
if (バージョン) namespace.VERSION = バージョン;
Module.modules[name] = 名前空間;
名前空間を返します。
};
// 名前が定義されているかどうかを確認します
Module.isDefined = function (name) {
Module.modules の名前を返します;
};
// バージョンを確認します
Module.require = function (name, version) {
if (!(Module.modules の名前)) throw new Error('モジュール ' 名前 ' が定義されていません');
if (!version) return;
var n = Module.modules[名前];
if (!n.VERSION || n.VERSION < version) throw new Error('version ' version ' 以上が必要です');
};
// モジュールをインポートします
Module.importSymbols = function (from) {
if (typeof form == 'string') from = Module.modules[from];
var to = Module.globalNamespace; //デフォルト
var シンボル = [];
var firstsymbol = 1;
if (arguments.length>1 && 引数の種類[1] == 'オブジェクト' && 引数[1] != null) {
to = 引数[1];
最初のシンボル = 2;
}
for (var a=firstsymbol; asymbols.push(arguments[a]);
}
if (symbols.length == 0) {
//デフォルトのエクスポートリスト
if (from.EXPORT) {
for (var i=0; ivar s = from.EXPORT[i];
to[s] = from[s];
}
戻る;
} else if (!from.EXPORT_OK) {
// EXPORT 配列 && EXPORT_OK 配列両方とも未定義
for (var s in from) {
to[s] = from[s];
戻る;
}
}
}
if (symbols.length > 0) {
var allowed;
if (from.EXPORT || form.EXPORT_OK) {
allowed = {};
if (from.EXPORT) {
for (var i=0; iallowed[from.EXPORT[i]] = true;
}
}
if (from.EXPORT_OK) {
for (var i=0; iallowed[form.EXPORT_OK[i] ] = true;
}
}
}
}
// シンボル
をインポートします (var i=0; ivar s = シンボル[私];
if (!(s in from)) throw new Error('シンボル ' s ' が定義されていません');
if (!!allowed && !(s in allowed)) throw new Error(s ' はパブリックではないため、インポートできません');
to[s] = form[s];
}
}
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート