コンピュータープログラミングの世界は、実際には、シンプルな部分を絶えず抽象化し、これらの抽象化を整理するプロセスです。 JavaScriptも例外ではありません。 JavaScriptを使用してアプリケーションを作成する場合、有名なオープンソースライブラリやフレームワークなど、他の人が書いたコードを使用します。私たちのプロジェクトが成長するにつれて、ますます多くのモジュールに依存する必要があります。現時点では、これらのモジュールを効果的に整理する方法が非常に重要な問題になりました。依存関係噴射は、コード依存性モジュールを効果的に整理する方法の問題を解決します。有名なフロントエンドフレームワークAngularjsなど、一部のフレームワークまたはライブラリで「依存関係注入」という用語を聞いたことがあるかもしれません。依存関係注射は非常に重要な機能の1つです。ただし、依存関係はまったく新しいものではなく、PHPなどの他のプログラミング言語では長い間存在しています。同時に、依存関係の注入は想像ほど複雑ではありません。この記事では、JavaScriptの依存関係噴射の概念を学び、「依存関係噴射スタイル」コードを書く方法を理解しやすい方法で説明します。
ターゲット設定
今すぐ2つのモジュールがあるとします。最初のモジュールの関数は、AJAX要求を送信することですが、2番目のモジュールの関数はルーティングとして使用することです。
コードコピーは次のとおりです。
var service = function(){
return {name: 'service'};
}
var router = function(){
return {name: 'router'};
}
この時点で、上記の2つのモジュールを使用する必要がある関数を書きました。
コードコピーは次のとおりです。
var dosomething = function(other){
var s = service();
var r = router();
};
ここでは、コードをより興味深いものにするために、このパラメーターはさらにいくつかのパラメーターを受信する必要があります。もちろん、上記のコードを使用できますが、いずれの側面からも、上記のコードの柔軟性は少し柔軟性が低いようです。使用する必要があるモジュール名がservicexmlまたはservicejsonになる場合はどうすればよいですか?または、テスト目的でいくつかの偽のモジュールを使用したい場合はどうなりますか?現時点では、関数自体を編集することはできません。したがって、最初にする必要があるのは、関数のパラメーターとして従属モジュールを渡すことです。コードは次のとおりです。
コードコピーは次のとおりです。
var dosomething = function(service、router、other){
var s = service();
var r = router();
};
上記のコードでは、必要なモジュールを完全に渡します。しかし、これは新しい問題を引き起こします。コードの兄弟部分の義理の方法を呼び出すとします。この時点で、3番目の依存関係が必要な場合はどうすればよいですか。現時点では、すべての関数コールコードを編集する賢明な方法ではありません。したがって、これを行うのに役立つコードが必要です。これは、依存関係インジェクターが解決しようとしている問題です。これで、目標を設定できます。
1.依存関係を登録できるはずです
2.依存関係インジェクターは関数を受信し、必要なリソースを取得できる関数を返す必要があります
3.コードは複雑ではないはずですが、シンプルでフレンドリーでなければなりません
4.依存関係インジェクターは、渡された関数スコープを維持する必要があります
5.渡された関数は、説明されている依存関係だけでなく、カスタムパラメーターを受信できるはずです
requirejs/amdメソッド
おそらく、あなたは有名な要件を聞いたことがあります。
コードコピーは次のとおりです。
定義(['service'、 'router']、function(service、router){
// ...
});
requirejsのアイデアは、最初に必要なモジュールを説明し、次に独自の機能を記述する必要があるということです。その中で、パラメーターの順序は非常に重要です。同様の構文を実装できるインジェクターと呼ばれるモジュールを記述する必要があるとします。
コードコピーは次のとおりです。
var dosomething = injector.resolve(['service'、 'router']、function(service、router、other){
expect(service()。name).to.be( 'service');
想像(router()。name).to.be( 'router');
(その他).to.be( 'other');
});
DOSOMTHING( "other");
継続する前に、注意すべきことの1つは、コードの正確性を確保するために、Assertion Library expect.jsを使用していることです。 TDD(テスト駆動型開発)に少し似ています。
次に、正式にインジェクターモジュールの書き込みを開始します。まず、アプリケーションのすべての部分で同じ機能を持つことができるように、モノマーである必要があります。
コードコピーは次のとおりです。
var injector = {
依存関係:{}、
登録:function(key、value){
this.dependencies [key] = value;
}、
Resolve:function(deps、func、scope){
}
}
このオブジェクトは非常にシンプルで、2つの機能とストレージ目的の変数のみがあります。私たちがする必要があるのは、DEPSアレイを確認してから、依存関係変数の答えを探すことです。残りは、.Applyメソッドを使用して、渡したFUNC変数を呼び出すことです。
コードコピーは次のとおりです。
Resolve:function(deps、func、scope){
var args = [];
for(var i = 0; i <deps.length、d = deps [i]; i ++){
if(this.dependencies [d]){
args.push(this.dependencies [d]);
} それ以外 {
新しいエラーをスローします( 'can/' t resolve ' + d);
}
}
return function(){
func.apply(scope || {}、args.concat(array.prototype.slice.call(arguments、0)));
}
}
スコープを指定する必要がある場合、上記のコードも正常に実行されます。
上記のコードでは、array.prototype.slice.call(arguments、0)の役割は、引数変数を実際の配列に変換することです。これまでのところ、私たちのコードはテストに完全に合格しました。しかし、ここでの問題は、必要なモジュールを2回記述する必要があり、任意に並べることができないことです。追加のパラメーターの後には常にすべての依存関係が続きます。
反射法
ウィキペディアの説明によると、反射は、オブジェクトが実行中に独自の構造と動作を変更できるという事実を指します。 JavaScriptでは、オブジェクトのソースコードを読み取り、ソースコードを分析する機能です。または、dosomething.toString()メソッドを呼び出す場合は、次の文字列を取得できます。
コードコピーは次のとおりです。
「機能(サービス、ルーター、その他){
var s = service();
var r = router();
} "
このようにして、この方法を使用する限り、必要なパラメーター、さらに重要なことに、それらの名前を簡単に取得できます。これは、AngularJSが依存関係注入を実装するために使用する方法でもあります。 AngularJSコードでは、次の正規表現を見ることができます。
コードコピーは次のとおりです。
/^function/s*[^/(]*/(/s*([^//)]*)/)/m
Resolveメソッドを次のコードに変更できます。
コードコピーは次のとおりです。
Resolve:function(){
var func、deps、scope、args = []、self = this;
func = arguments [0];
deps = func.toString()。match(/^function/s*[^/(]*/(/s*([^/)]*)/)/m)[1] .replace(//g、 '').split( '、');
scope = arguments [1] || {};
return function(){
var a = array.prototype.slice.call(arguments、0);
for(var i = 0; i <deps.length; i ++){
var d = deps [i];
args.push(self.dependencies [d] && d!= ''?self.dependencies [d]:a.shift());
}
func.apply(scope || {}、args);
}
}
上記の正規表現を使用して定義した関数に一致し、次の結果を得ることができます。
コードコピーは次のとおりです。
["function(service、router、other)"、 "service、router、その他"]
この時点では、2番目のアイテムのみが必要です。しかし、余分なスペースを削除してストリングをスライスしたら、DEPSアレイを取得します。次のコードは、変更した部分です。
コードコピーは次のとおりです。
var a = array.prototype.slice.call(arguments、0);
...
args.push(self.dependencies [d] && d!= ''?self.dependencies [d]:a.shift());
上記のコードでは、依存関係プロジェクトを通過します。依存関係が不足している場合、依存関係プロジェクトに部品が欠落している場合、引数オブジェクトからそれを取得します。配列が空の配列である場合、シフトメソッドを使用すると、エラーを投げることなく未定義のみが返されます。これまでのところ、インジェクターの新しいバージョンは次のようになります。
コードコピーは次のとおりです。
var dosomething = injector.resolve(function(service、other、router){
expect(service()。name).to.be( 'service');
想像(router()。name).to.be( 'router');
(その他).to.be( 'other');
});
DOSOMTHING( "other");
上記のコードでは、依存関係の順序を自由に混同することができます。
しかし、完璧なものはありません。反射法の依存関係に非常に深刻な問題があります。コードが簡素化されたときにエラーが発生します。これは、コードの簡素化中に、パラメーターの名前が変更され、依存関係が解決されるためです。例えば:
コードコピーは次のとおりです。
var dosomething = function(e、t、n){var r = e(); var i = t()}
したがって、Angularjsのように、次のソリューションが必要です。
コードコピーは次のとおりです。
var dosomething = injector.resolve(['service'、 'router'、function(service、router){
}]);
これは、最初に見たAMDソリューションに非常に似ているため、上記の2つの方法を統合できます。最終コードは次のとおりです。
コードコピーは次のとおりです。
var injector = {
依存関係:{}、
登録:function(key、value){
this.dependencies [key] = value;
}、
Resolve:function(){
var func、deps、scope、args = []、self = this;
if(typeof arguments [0] === 'string'){
func = arguments [1];
deps = arguments [0] .replace( / / g、 '').split( '、');
scope = arguments [2] || {};
} それ以外 {
func = arguments [0];
deps = func.toString()。match(/^function/s*[^/(]*/(/s*([^/)]*)/)/m)[1] .replace(//g、 '').split( '、');
scope = arguments [1] || {};
}
return function(){
var a = array.prototype.slice.call(arguments、0);
for(var i = 0; i <deps.length; i ++){
var d = deps [i];
args.push(self.dependencies [d] && d!= ''?self.dependencies [d]:a.shift());
}
func.apply(scope || {}、args);
}
}
}
Resolveメソッドのこのバージョンは、2つまたは3つのパラメーターを受け入れることができます。これがテストコードです:
コードコピーは次のとおりです。
var dosomething = injector.resolve( 'router ,, service'、function(a、b、c){
(a()。name).to.be( 'router');
期待(b).to.be( 'other');
(c()。name).to.be( 'service');
});
DOSOMTHING( "other");
2つのコンマの間には何もないことに気づいたかもしれませんが、それは間違いではありません。この空室は他のパラメーターに残されています。これが、パラメーターの順序を制御する方法です。
結論
上記のコンテンツでは、JavaScriptに依存関係注入のいくつかの方法を導入しました。この記事が、依存関係噴射技術の使用を開始し、依存関係噴射スタイルのコードを書き始めるのに役立つことを願っています。