検索
ホームページウェブフロントエンドjsチュートリアルJavascript_javascript スキルにおける依存関係の挿入についての深い理解


遅かれ早かれ、他の開発者の抽象化を使用する必要があります。つまり、他の人のコードに依存することになります。依存関係のない (依存関係のない) モジュールが望ましいですが、それを実現するのは困難です。あなたが作成する素晴らしいブラック ボックス コンポーネントであっても、多かれ少なかれ何かに依存しています。ここで依存性注入が登場します。依存関係を効果的に管理する機能は、今や絶対的に必要なものになっています。この記事では、この問題についての私の調査とその解決策のいくつかを要約します。

1. 目標
2 つのモジュールがあると想像してください。 1 つ目は 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();
};

見た目をさらに面白くするために、この関数は 1 つのパラメーターを受け入れます。もちろん、上記のコードを完全に使用することはできますが、明らかに十分な柔軟性がありません。 ServiceXML または ServiceJSON を使用したい場合、またはテスト モジュールが必要な場合はどうすればよいでしょうか。関数本体を編集するだけでは問題を解決できません。まず、関数のパラメーターを通じて依存関係を解決できます。つまり、
コードをコピー コードは次のとおりです。

var doSomething = function(service) , router, other ) {
var s = service();
var r = router();
};

追加のパラメータを渡すことで目的を達成しますが、これは新たな問題をもたらすことになる。 doSomething メソッドがコード全体に散在している場合を想像してください。依存関係を変更する必要がある場合、関数を呼び出すすべてのファイルを変更することはできません。

これを行うのに役立つツールが必要です。これは依存関係注入が解決しようとしている問題です。依存関係注入ソリューションが達成すべき目標をいくつか書き留めてみましょう:

依存関係を登録できるはずです
1. インジェクションは関数を受け取り、必要な関数を返す必要があります
2. あまり多くを書くことはできません - 合理化された美しい構文が必要です
3 .インジェクションは渡された関数のスコープを維持する必要があります
4. 渡された関数は依存関係の説明だけでなくカスタムパラメータを受け入れることができる必要があります
5. これは完璧なチェックリストです。
3. RequireJS/AMD メソッド
RequireJS について聞いたことがあるかもしれませんが、これは依存関係の注入を解決するための良い選択です。

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

define(['service', 'router ']、関数(サービス、ルーター) {ここでのパラメータの順序は重要です。上で述べたように、同じ構文を受け入れる injector というモジュールを作成しましょう。



コードをコピー
コードは次のとおりです。var doSomething = injector.resolve([' service', 'router'], function(service, router, other) { Expect(service().name).to.be('Service');
Expect(router().name)。 to.be ('Router');
Expect(other).to.be('Other');
});

doSomething("Other");
すべきだdoSomething 関数本体の内容を明確に説明するために、少し TDD (テスト駆動開発) メソッドを反映して、作成したコードが期待どおりに動作することを確認するために、expect.js (アサーション ライブラリ) を使用します。
インジェクター モジュールから始めましょう。これは優れたシングルトン パターンなので、プログラムのさまざまな部分でうまく機能します。




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

var injector = {
依存関係: {},
register: function(key, value) {
this.dependency[key] = value;
},
解決: function(deps, func,scope) {

}
}


これは、プロパティを保存するための 2 つのメソッドを備えた非常に単純なオブジェクトです。私たちが行うことは、deps 配列をチェックし、依存関係変数で答えを検索することです。残っているのは、.apply メソッドを呼び出して、前の func メソッドから引数を渡すことだけです。
コードをコピー コードは次のとおりです。

resolve: function(deps, func,scope ) {
var args = [];
for(var i=0; i if(this.dependency[d]) {
args.push (this.Dependency [d]);
} else {
新しいエラーをスロー ('解決できません' d);
func.apply(scope || {}, args.concat(Array.prototype.slice.call(arguments, 0)));
}
}

スコープはオプションです はい、Array.prototype.slice.call(arguments, 0)引数変数を実数配列に変換するには必要です。ここまでは順調ですね。私たちのテストは合格しました。この実装の問題は、必要な部分を 2 回記述する必要があり、その順序を間違えることができないことです。追加のカスタム パラメーターは常に依存関係の後に来ます。
4. リフレクション方法
Wikipedia の定義によれば、リフレクションとは、実行時にオブジェクトの構造と動作を検査および変更するプログラムの機能を指します。簡単に言えば、JavaScript のコンテキストでは、これは特にオブジェクトまたは関数のソース コードを読み取って分析することを指します。記事の冒頭で述べた doSomething 関数を完成させましょう。 doSomething.tostring() をコンソールに出力した場合。次の文字列を取得します:



コードをコピーします コードは次のとおりです:" function (service , router, other) {
var s = service();
var r = router();
}"

このメソッドによって返される文字列は、次の機能を提供します。パラメータを走査すること、そしてさらに重要なことに、パラメータの名前を取得できることです。これは実際に、Angular が依存関係の注入を実装する方法です。私は少し怠け者だったので、Angular コードのパラメータを取得するための正規表現を直接インターセプトしました。


コードをコピー コードは次のとおりです:/^functions*[^(]* (s* ([^)]*))/m
解決コードは次のように変更できます:


コードをコピー コードは次のとおりです: resolve: function() {
var func, deps,scope, args = [], self = this;
func = argument [0];
deps = func.toString().match(/^functions*[^(]*(s*([^)]*))/m)[1].replace(/ /g, '').split (',');
スコープ = argument[1] {};
return function() {
var a = Array.prototype.slice.call(arguments, 0) );
for(var i=0; i var d = deps[i];
args.push(self.dependency[d] && d != ' ' ? self.dependency [d]: a.shift());
}
func.apply(scope || {}, args);
}
}

正規表現を実行します。 other)", "service, router, other"]
の結果
必要なのは 2 番目の項目だけのようです。スペースをクリアして文字列を分割すると、deps 配列が得られます。大きな変更点は 1 つだけです:
コードをコピーします コードは次のとおりです:

var a = Array.prototype .slice.call(arguments, 0);
...
args.push(self.dependency[d] && d != '' ? self.dependency[d] : a. SHIFT());

依存関係配列をループし、欠落している項目が見つかった場合は引数オブジェクトから取得しようとします。ありがたいことに、配列が空の場合、shift メソッドはエラーをスローするのではなく、単に未定義を返します (Web のアイデアのおかげです)。新しいバージョンのインジェクターは次のように使用できます:
コードをコピーします コードは次のとおりです:

var doSomething = injector.resolve(function(service, other, router) {
Expect(service().name).to.be('Service');
Expect(router().name ).to.be( 'ルーター');
Expect(other).to.be('その他');
});
doSomething("その他");

依存関係を書き直す必要はなく、順序が崩れる可能性があります。それは今でも機能しており、Angular の魔法を再現することに成功しました。

しかし、このアプローチは完璧ではなく、反射型注射では非常に大きな問題となります。圧縮するとパラメーター名が変更され、正しいマッピングを維持できなくなるため、ロジックが壊れます。たとえば、 doSometing() は圧縮すると次のようになります:

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

var doSomething=function(e,t,n){var r=e();var i=t()}
Angular チームが提案した解決策は次のようになります:

var doSomething = injector.resolve(['service', 'router', function(service, router) {

}]);


これは、最初のソリューションとよく似ています。より良い解決策が見つからなかったので、2 つのアプローチを組み合わせることにしました。以下はインジェクターの最終バージョンです。
コードをコピー コードは次のとおりです:

var injector = {
依存関係: {},
register: function(key, value) {
this.dependency[key] = value;
},
solve: function() {
var func, deps,scope , args = [], self = this;
if(引数の種類[0] === 'string') {
func = argument[1];
deps = argument[0].replace( / /g , '').split(',');
スコープ = 引数[2] || {};
} else {
func = argument[0];
deps = func.toString ().match(/^functions*[^(]*(s*([^)]*))/m)[1].replace(/ /g, '').split(',' );
スコープ = 引数[1] i=0; i
var d = deps[ i]; : a.shift());

解決ビジターは 2 つまたは 3 つのパラメーターを受け入れます。パラメーターが 2 つある場合、実際にはこの記事で前述したものと同じです。ただし、パラメータが 3 つある場合は、最初のパラメータが変換され、deps 配列が埋められます。テスト例は次のとおりです:
コードをコピー コードは次のとおりです:

var doSomething = injector.resolve('router,,service', function(a, b, c) {
Expect(a().name) ).to .be('Router');
Expect(b).to.be('Other');
Expect(c().name).to.be('Service');
} );
doSomething("Other");

最初のパラメータの後にカンマが 2 つあることに気づくかもしれませんが、これはタイプミスではないことに注意してください。 null 値は実際には「Other」パラメータ (プレースホルダ) を表します。これは、パラメーターの順序を制御する方法を示しています。

5. スコープを直接注入する
操作関数 (つまり this オブジェクト) のスコープに関係する 3 番目の注入変数を使用することがあります。したがって、多くの場合、この変数を使用する必要はありません。

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

var injector = {
依存関係: {},
register: function(key, value) {
this.dependency[key] = value;
},
solve: function(deps, func,scope) {
var args = [ ];
スコープ = スコープ {};
for(var i=0; i if(this.dependency [d] ) {
scope[d] = this.dependency[d]; }
return function() {
func.apply(scope || {}, Array.proto type.slice.call(引数、0)); スコープに依存関係を追加するだけです。この利点は、開発者が依存関係パラメーターを記述する必要がなくなり、依存関係パラメーターがすでに関数スコープの一部になっているということです。




コードをコピー

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

var doSomething = injector.resolve([' service', 'router'], function(other) { Expect(this.service().name).to.be('Service'); Expect(this.router().name)。 to.be ('ルーター'); Expect(other).to.be('その他');});doSomething("その他");
6.結論
実際、私たちのほとんどは依存性注入を使用したことがありますが、それに気づいていませんでした。この用語を知らなくても、おそらくコード内で何百万回も使用したことがあるでしょう。この記事で理解を深めていただければ幸いです。
声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

20+道必知必会的Vue面试题(附答案解析)20+道必知必会的Vue面试题(附答案解析)Apr 06, 2021 am 09:41 AM

本篇文章整理了20+Vue面试题分享给大家,同时附上答案解析。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!