深入了解Javascript中的依赖注入

深入了解Javascript中的依赖注入
迟早,你需要使用其他开发者,你依靠别人的代码的抽象的结果。我喜欢依赖免费的模块(无依赖性),但这是很难实现的,即使美丽的黑盒组件,你创造的是更多或更少的依赖的东西。这是什么取决于注射。它有效地管理依靠现在的能力是绝对必要的。本文总结了我和一些解决问题的探索。

1。目标
假设我们有两个模块,第一个是Ajax请求服务(服务),第二个是路由器。
复制代码代码如下所示:
var服务=函数(){()
返回{名称:服务};
}
var路由器=函数(){()
返回{名称:'router};
}
我们还有另外一个函数需要用于这两个模块。
复制代码代码如下所示:
VaR做=功能(其他){
var =服务();
var =路由器();
};
让它看起来更有趣,这个函数接受一个参数。当然,我们完全可以利用上面的代码,但这显然不够灵活。如果我们想用servicexml或servicejson,或者我们需要一些测试模块。我们不能仅通过编辑功能体解决问题。首先,我们可以通过函数的参数,是解决依赖关系:
复制代码代码如下所示:
VaR做=功能(服务、路由器、其他){
var =服务();
var =路由器();
};
我们做什么,我们想通过额外的参数,但是,这会带来新的问题。想象一下,如果我们做的方法是分散在我们的代码。如果我们需要改变依赖条件,让我们改变所有文件,调用函数是不可能的。

我们需要一个工具来帮助我们完成这些工作,这是依赖注入试图解决的问题,让我们写下依赖注入解决方案应该实现的一些目标:

我们应该能够注册我们的依赖项。
1。注入应该接受一个函数并返回我们需要的函数。
2。我们不能写得太多-我们需要精简漂亮的语法。
三.注入应保持传递函数的范围。
4。传递函数应该能够接受自定义参数,而不仅仅是依赖描述。
5。可以是一个完美的列表,让我们在下面做。
三、requirejs / AMD的方法
你可能听说过RequireJS早期,解决依赖注入是一个不错的选择。
复制代码代码如下所示:
定义({服务','router},功能(服务、路由器){

});
这个想法是先描述所需的依赖项,然后写出你的函数。参数的顺序在这里非常重要。如上所述,我们编写一个模块,称为注入器,它可以接受相同的语法。
复制代码代码如下所示:
VaR做= injector.resolve({服务','router},功能(服务、路由器、其他){
期望(服务()。名称)。To.be(服务的);
期望(路由器()。名称)。To.be('router);
期望(其他)To.be(其他的);
});
做(其他);
在我继续之前,我应该解释做功能的内容。我用expect.js(断言库)来确保我的代码的行为,正如我所预料的一样,反映了一个小的TDD(测试驱动开发)的方法。
在这里,我们开始我们的喷射器模块,这是一个非常好的单模式,所以它在我们的程序的不同部分工作得很好。
复制代码代码如下所示:
var注入器{ {
依赖项:{ },
寄存器:函数(键,值){
这个依赖项{键} =值;
},
解决:功能(依赖、功能、范围){

}
}
这是一个非常简单的对象,有两种方法,属性用于存储它。我们要做的是检查该阵列在依赖变量搜索答案。剩下的只有参数调用。应用方法和传递函数法。
复制代码代码如下所示:
解决:功能(依赖、功能、范围){
var args = { };
对于(var i = 0;i < deps.length,a DEPS {我};i++){
如果(这个依赖项{ }){
Args.push(这个依赖{d});
{人}
把新的错误(无法解决+ D);
}
}
返回函数(){
Func.apply(范围| | { },args.concat(array.prototype.slice.call(参数0)));
}
}
范围是可选的,并array.prototype.slice.call(参数0)转换成一个真正的数组参数是必要的。到目前为止,这是很好的。我们的测试已通过,这个实现的问题是我们需要写的所需配件两部分,我们不能把他们的订单。额外的自定义参数总是位于后的依赖。

四,反射法
根据维基百科的定义反射指程序在运行时检查和修改一个对象的结构和行为。在一个简单的方法,在Javascript中,这指的是对象或函数读取源代码的分析,让我们完成一些功能在文章开头提到的,如果你在控制台输出dosomething.tostring(),你会得到下面的字符串:
复制代码代码如下所示:
函数(服务,路由器,其他){
var =服务();
var =路由器();
}
此方法返回的字符串使我们能够遍历参数,更重要的是获得它们的名称。这实际上是角实现了依赖注入的方式。我偷了一点懒惰,截获了角编码中参数的正则表达式。
复制代码代码如下所示:
函数({ *({ })})
我们可以修改以下的解析代码:
复制代码代码如下所示:
解析:函数(){
VAR函数,依赖,范围,args =自我=这{ };
参数= { 0 };
稀释每股收益= func.tostring(。比赛( / ^功能 * { ^ )(} * ( *({ ^ )}×),{ 1 }。取代( / / / G M)),分(),。');
参数范围= { 1 } | | { };
返回函数(){
创建一个array.prototype.slice.call(参数0);
对于(var i = 0;i < deps.length;i++){
var a DEPS {我};
Args.push(自我依赖{d} D!= '自我。依赖{d}:a.shift());
}
Func.apply(范围| | { },args);
}
}
我们的正则表达式的结果如下:
复制代码代码如下所示:
函数(服务,路由器,其他)
看来我们只需要二项。一旦我们知道空间和拆分字符串,我们得到该数组只有一个大的变化:
复制代码代码如下所示:
创建一个array.prototype.slice.call(参数0);

Args.push(自我依赖{d} D!= '自我。依赖{d}:a.shift());
我们遍历依赖数组,如果我们找到丢失的项,我们尝试从参数对象中获取它。幸好,当数组为空时,移位方法只返回到未定义的位置,而不是抛出错误(这是由于Web的概念):
复制代码代码如下所示:
VaR做= injector.resolve(功能(服务,其他路由器){
期望(服务()。名称)。To.be(服务的);
期望(路由器()。名称)。To.be('router);
期望(其他)To.be(其他的);
});
做(其他);
没有必要改写依赖性,他们的秩序会被打乱,它仍然是有效的,我们已经成功地复制了角的魔力。

然而,这种方法是不完美的,这是反射式注入一个非常大的问题。压缩会破坏我们的逻辑,因为它改变的参数的名称,我们就不能保持正确的映射关系。例如,dosometing()可能看起来像压缩后:
复制代码代码如下所示:
VaR做=功能(E,T,N){ var r = E();var i = t()}
角团队提出的解决方案看起来像:

VaR做= injector.resolve({服务','router功能(服务、路由器){

});
它看起来像我们开始的解决方案,我找不到更好的解决方案,所以我决定把这两种方法结合起来。
复制代码代码如下所示:
var注入器{ {
依赖项:{ },
寄存器:函数(键,值){
这个依赖项{键} =值;
},
解析:函数(){
VAR函数,依赖,范围,args =自我=这{ };
如果(typeof论点{ 0 } = 'String'){
参数= { 1 };
稀释每股收益=论点{ 0 }。取代( / /克,),Split(',');
参数范围= { 2 } | | { };
{人}
参数= { 0 };
稀释每股收益= func.tostring(。比赛( / ^功能 * { ^ )(} * ( *({ ^ )}×),{ 1 }。取代( / / / G M)),分(),。');
参数范围= { 1 } | | { };
}
返回函数(){
创建一个array.prototype.slice.call(参数0);
对于(var i = 0;i < deps.length;i++){
var a DEPS {我};
Args.push(自我依赖{d} D!= '自我。依赖{d}:a.shift());
}
Func.apply(范围| | { },args);
}
}
}
解决客人接受两个或三个参数,如果有两个参数,它实际上是,在前面的文章一样。然而,如果有三个参数,它将第一个参数转换和填充该数组,以下是一个测试的例子:
复制代码代码如下所示:
VaR做= injector.resolve('router,服务,功能(A,B,C){
(一)期望(名称)To.be('router);
期望(B)To.be(其他的);
期望(C()。名称)。To.be(服务的);
});
做(其他);
您可能注意到,在前两个参数之后:注意这不是逗号。空值实际上代表另一个参数(占位符)。这说明了我们如何控制参数的顺序。

五。直接注入作用
有时我使用第三个注入变量,这些变量涉及操作函数的范围(换句话说,就是这个对象),所以很多时候你不需要使用这个变量。
复制代码代码如下所示:
var注入器{ {
依赖项:{ },
寄存器:函数(键,值){
这个依赖项{键} =值;
},
解决:功能(依赖、功能、范围){
var args = { };
范围=范围| | { };
对于(var i = 0;i < deps.length,a DEPS {我};i++){
如果(这个依赖项{ }){
范围{此};
{人}
把新的错误(无法解决+ D);
}
}
返回函数(){
Func.apply(范围| | { },array.prototype.slice.call(参数0));
}
}
}
我们所做的只是将依赖性添加到作用域中,这样做的好处是开发人员不必编写相关参数,它们已经是函数作用域的一部分。
复制代码代码如下所示:
VaR做= injector.resolve({服务','router},功能(其他){ {)
期望(this.service()。名称)。To.be(服务的);
期望(this.router()。名称)。To.be('router);
期望(其他)To.be(其他的);
});
做(其他);
六、结束语
事实上,我们大多数人过去都依赖注射,但我们没有意识到,即使你不知道这个术语,你也可以在代码中使用数百万次,我希望这篇文章能加深你对它的理解。
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部