JavaScript中依赖注入详细解析
作者:网络转载 发布时间:[ 2015/8/11 10:55:05 ] 推荐标签:WEB开发 组织代码
计算机编程的世界其实是一个将简单的部分不断抽象,并将这些抽象组织起来的过程。JavaScript也不例外,在我们使用JavaScript编写应用时,我们是不是都会使用到别人编写的代码,例如一些的开源库或者框架。随着我们项目的增长,我们需要依赖的模块变得越来越多,这个时候,如何有效的组织这些模块成了一个非常重要的问题。依赖注入解决的正是如何有效组织代码依赖模块的问题。你可能在一些框架或者库种听说过“依赖注入”这个词,比如说的前端框架AngularJS,依赖注入是其中一个非常重要的特性。但是,依赖注入根本不是什么新鲜玩意,它在其他的编程语言例如PHP中已经存在已久。同时,依赖注入也没有想象种那样复杂。在本文中,我们将一起来学习JavaScript中的依赖注入的概念,深入浅出的讲解如何编写“依赖注入风格”的代码。
目标设定
假设我们现在拥有两个模块。第一个模块的作用是发送Ajax请求,而第二个模块的作用则是用作路由。
var service = function() {
return { name: 'Service' };
}
var router = function() {
return { name: 'Router' };
}
这时,我们编写了一个函数,它需要使用上面提到的两个模块:
var doSomething = function(other) {
var s = service();
var r = router();
};
在这里,为了让我们的代码变得有趣一些,这个参数需要多接收几个参数。当然,我们完全可以使用上面的代码,但是无论从哪个方面来看上面的代码都略显得不那么灵活。要是我们需要使用的模块名称变为ServiceXML或者ServiceJSON该怎么办?或者说如果我们基于测试的目的想要去使用一些假的模块改怎么办。这时,我们不能仅仅去编辑函数本身。因此我们需要做的第一件事情是将依赖的模块作为参数传递给函数,代码如下所示:
var doSomething = function(service, router, other) {
var s = service();
var r = router();
};
在上面的代码中,我们完全传递了我们所需要的模块。但是这又带来了一个新的问题。假设我们在代码的哥哥部分都调用了doSomething方法。这时,如果我们需要第三个依赖项该怎么办。这个时候,去编辑所有的函数调用代码并不是一个明智的方法。因此,我们需要一段代码来帮助我们做这件事情。这是依赖注入器试图去解决的问题。现在我们可以来定下我们的目标了:
我们应该能够去注册依赖项
依赖注入器应该接收一个函数,然后返回一个能够获取所需资源的函数
代码不应该复杂,而应该简单友好
依赖注入器应该保持传递的函数作用域
传递的函数应该能够接收自定义的参数,而不仅仅是被描述的依赖项
requirejs/AMD方法
或许你已经听说过了大名鼎鼎的requirejs,它是一个能够很好的解决依赖注入问题的库:
define(['service', 'router'], function(service, router) {
// ...
});
requirejs的思想是首先我们应该去描述所需要的模块,然后编写你自己的函数。其中,参数的顺序很重要。假设我们需要编写一个叫做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的函数体中我们使用了expect.js这个断言库来确保代码的正确性。这里有一点类似TDD(测试驱动开发)的思想。
现在我们正式开始编写我们的injector模块。首先它应该是一个单体,以便它能够在我们应用的各个部分都拥有同样的功能。
var injector = {
dependencies: {},
register: function(key, value) {
this.dependencies[key] = value;
},
resolve: function(deps, func, scope) {
}
}
这个对象非常的简单,其中只包含两个函数以及一个用于存储目的的变量。我们需要做的事情是检查deps数组,然后在dependencies变量种寻找答案。剩余的部分,则是使用.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]);
} else {
throw new Error('Can't resolve ' + d);
}
}
return function() {
func.apply(scope || {}, args.concat(Array.prototype.slice.call(arguments, 0)));
}
}
如果你需要指定一个作用域,上面的代码也能够正常的运行。
相关推荐
更新发布
功能测试和接口测试的区别
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