JavaScript中依赖注入详细解析
作者:网络转载 发布时间:[ 2015/8/11 10:55:05 ] 推荐标签:WEB开发 组织代码
在上面的代码中,Array.prototype.slice.call(arguments, 0)的作用是将arguments变量转换为一个真正的数组。到目前为止,我们的代码可以完美的通过测试。但是这里的问题是我们必须要将需要的模块写两次,而且不能够随意排列顺序。额外的参数总是排在所有的依赖项之后。
反射(reflection)方法
根据维基百科中的解释,反射(reflection)指的是程序可以在运行过程中,一个对象可以修改自己的结构和行为。在JavaScript中,简单来说是阅读一个对象的源码并且分析源码的能力。还是回到我们的doSomething方法,如果你调用doSomething.toString()方法,你可以获得下面的字符串:
"function (service, router, other) {
var s = service();
var r = router();
}"
这样一来,只要使用这个方法,我们可以轻松的获取到我们想要的参数,以及更重要的一点是他们的名字。这也是AngularJS实现依赖注入所使用的方法。在AngularJS的代码中,我们可以看到下面的正则表达式:
/^functions*[^(]*(s*([^)]*))/m
我们可以将resolve方法修改成如下所示的代码:
resolve: function() {
var func, deps, scope, args = [], self = this;
func = arguments[0];
deps = func.toString().match(/^functions*[^(]*(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, other"]
此时,我们只需要第二项。但是一旦我们去除了多余的空格并以,来切分字符串以后,我们得到了deps数组。下面的代码是我们进行修改的部分:
var a = Array.prototype.slice.call(arguments, 0);
...
args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());
在上面的代码中,我们遍历了依赖项目,如果其中有缺失的项目,如果依赖项目中有缺失的部分,我们从arguments对象中获取。如果一个数组是空数组,那么使用shift方法将只会返回undefined,而不会抛出一个错误。到目前为止,新版本的injector看起来如下所示:
var doSomething = injector.resolve(function(service, other, router) {
expect(service().name).to.be('Service');
expect(router().name).to.be('Router');
expect(other).to.be('Other');
});
doSomething("Other");
在上面的代码中,我们可以随意混淆依赖项的顺序。
但是,没有什么是完美的。反射方法的依赖注入存在一个非常严重的问题。当代码简化时,会发生错误。这是因为在代码简化的过程中,参数的名称发生了变化,这将导致依赖项无法解析。例如:
var doSomething=function(e,t,n){var r=e();var i=t()}
因此我们需要下面的解决方案,像AngularJS中那样:
var doSomething = injector.resolve(['service', 'router', function(service, router) {
}]);
这和一开始看到的AMD的解决方案很类似,于是我们可以将上面两种方法整合起来,终代码如下所示:
var injector = {
dependencies: {},
register: 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] || {};
} else {
func = arguments[0];
deps = func.toString().match(/^functions*[^(]*(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方法可以接受两个或者三个参数。下面是一段测试代码:
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");
你可能注意到了两个逗号之间什么都没有,这并不是错误。这个空缺是留给Other这个参数的。这是我们控制参数顺序的方法。
结语
在上面的内容中,我们介绍了几种JavaScript中依赖注入的方法,希望本文能够帮助你开始使用依赖注入这个技巧,并且写出依赖注入风格的代码。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
JavaScript有这几种测试分类JavaScript深入之创建对象的多种方式以及优缺点Prepack?JavaScript代码优化工具2017值得一瞥的JavaScript相关技术趋势JavaScript深入之从原型到原型链在Node.js中看JavaScript的引用每个前端开发者必会的二十个JavaScript面试题JavaScript 基础阶段测试题(含答案)说说如何用JavaScript实现一个模板引擎JavaScript四种调用模式和this示例介绍一道面试题引发的对JavaScript类型转换的思考JavaScript与Java、PHP的比较怎样写一个能同时用于Node和浏览器的JavaScript包?JavaScript 测试?单元vs功能vs集成测试Javascript项目单元测试小结简单易操作的跨浏览器JavaScript单元测试解决方案
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南