AngularJS——依赖注入
依赖注入
依赖注入(DI)是一个经典的设计模式, 主要是用来处理组件如何获得依赖的问题。关于DI,推荐阅读Martin Flower的文章(http://martinfowler.com/articles/injection.html )。
Angular注入器会负责创建angular组件,解决组件之间的依赖以及依赖注入等职责。
使用依赖注入
依赖注入在angular应用代码中使用很频繁。我们可以在定义组件或者在模块的run和config块中使用。
- 可在angular组件(控制器、服务、过滤器、指令、动画等)的构造方法或工厂方法中声明依赖关系。可以向这些组件中注入服务(service)或者值(value)类型的依赖。
- 可为控制器添加一些特殊的依赖,我们将在下面具体介绍。
- 可在模块的run方法中定义依赖,可被注入的依赖包括服务(service)、值(value)和参量(constant)。注意.在run方法中不能注入"provider"类型的依赖.
- 可在模块的config中声明“provider”和“constant”类型的依赖,但不能注入service和value组件。
工厂方法
angular中的指令、服务或者过滤器可以通过工厂方法定义。工厂方法是模块(module)的子方法。通常推荐按下面的方式使用工厂方法:
模块方法
angular模块提供了config和run方法方便开发者为模块添加配置和运行上下文的设置。和工厂方法类似,我们可以在config和run方法中定义依赖。例如:
控制器
控制器的构造方法主要用来定义模板中所用的模型数据和行为。通常推荐按如下用法使用构造器:
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
...
}]);
angular应用中可存在多个控制器实例,而服务组件是单例.
除了service, value类的依赖, 控制器中还注入一下依赖:
- $scope: 控制器是与某个DOM元素通过作用域相关联。其他类型的组件只能访问$rootScope服务。
- resolves : 如果在路由中实例化控制器,那么在路由里面解析的任何值域都可以作为依赖注入到控制器。
依赖注解
angular在执行某些方法(例如在服务的工厂方法、控制器构造方法)时会借助注入器(injector)。 因此我们需要在这些方法中加入标注来通知注入器哪些依赖需要被注入。可以通过以下三种方式注入服务:
- 通过数组标注在方法的参数中声明依赖(优先考虑)
- 定义在控制器构造方法的$inject属性中
- 通过方法参数名隐式的添加(有些注意事项)
数组标注
优先考虑用该方式为组件定义依赖,例如:
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) { // ... }]);
在代码中通过在第二个数组类型的参数中声明了'$scope','greeter'等依赖,数组最后一个元素为实际的构造方法,注意在构造方法的参数列表与其面的数组元素是一一对应的。
$inject属性
我们还可以通过为控制器的构造方法添加$inject属性,并在该属性中添加依赖的方式定义依赖。
注意$inject中依赖的顺序与构造方法中的参数需保持一致。
隐式声明依赖
最简单的声明依赖的方式就是让设构造方法的参数与依赖的名字一样。
someModule.controller('MyController', function($scope, greeter) { // ... });
注入器可以从函数的参数名中推断所依赖的服务。上面的函数中声明了$scope和greeter服务作为依赖。 这种方式可是代码更加简洁,但这种方式不能和Javascript的代码混淆器一起使用。可以通过ng-annotate在minifying之前隐式的添加依赖。
Strict Mode
通过在ng-app所在的DOM元素中添加ng-strict-di切换到严格的依赖注入模式:
Strict模式下使用隐式的标注会报错, 例如:
当willBreak服务被实例化时,factory方法中由于参数$rootScope在前面的数组元素中声明而导致与依赖不匹配会报错。特别是使用ng-annotate时,该模式会保证所有应用组件的依赖被显示地声明。
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
如果用angular.bootstrap手动启动angular应用,我们可以通过设置config中的strictDi属性,启动strict模式。
依赖注入的优点
在介绍依赖注入的优点之前我们简要介绍一下依赖注入模式。
我们可以通过三种方式让组件获得所需的依赖:
1. 在组件中创建依赖,例如通过new
2. 在全局上下文环境中查找依赖,通常为全局变量
3. 在组件需要依赖的时候自动注入依赖,例如Spring、Angular
前面两种方式都无法避免硬编码, 这样会增加代码的耦合度,变更会非常麻烦,也不利于测试。
第三种方式是最可行的,这种方式将查找注入依赖的职责统一转给了另一方方(容器)。
function SomeClass(greeter) {
this.greeter = greeter;
} SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}
在上面的代码中, SomeClass并没有关注创建和查找greeter依赖,而只是简单的作为构造器的参数传入。这样负责创建SomeClass实例的代码会负责创建并注入依赖。
angular注入器($injector类似于spring容器)负责创建、查找注入依赖, 每个module都会有自己的注入器。
如下代码,可在module方法的第二参数中声明依赖的模块,通过工厂方法构造greeter服务,该服务依赖于$window服务, greeter服务包含了greet方法调用$wondow服务。
我们还可以通过如下代码创建一个注入器,里面包含了myModule和ng模块, 这样我们就可以获得这两个模块中组件。
var injector = angular.injector(['myModule', 'ng']); var greeter = injector.get('greeter');
似乎是解决了硬编码注入依赖的问题,但新的问题是injector如何贯穿整个应用。通过模板中声明式的标签,我们可以解决新的问题。
Angular在编译模板阶段为ng-controller指令实例化MyController以及注入相关的依赖。
AngularJS——依赖注入的更多相关文章
- AngularJS依赖注入
<html> <head> <meta charset="utf-8"> <title>AngularJS 依赖注入</tit ...
- AngularJS 依赖注入
依赖注入(Dependency Injection,简称DI)是一种软件设计模式,在这种模式下,一个或更多的依赖(或服务)被注入(或者通过引用传递)到一个独立的对象(或客户端)中,然后成为了该 ...
- 关于angularjs依赖注入的整理
初学angularjs阶段,刚刚看到菜鸟教程的angularjs依赖注入.现在整理一下: 1.含义:一个或更多的依赖(可以理解为模块关系依赖)或服务(分为内建服务[例如$http,$tiomeout等 ...
- AngularJS开发指南10:AngularJS依赖注入的详解
依赖注入是一种软件设计模式,用来处理代码的依赖关系. 一般来说有三种方法让函数获得它需要的依赖: 它的依赖是能被创建的,一般用new操作符就行. 能够通过全局变量查找依赖. 依赖能在需要时被导入. 前 ...
- (五)Angularjs - 依赖注入
如何找到API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. 比如,AngularJS暴露了一个全局对象:angu ...
- AngularJS - 依赖注入(Dependency Injection)
点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ 依赖注入 依赖注入是软件设计模式中的一部分,用于处理组件是如何得到它说依赖的其它组件的. ...
- angularjs 依赖注入--自己学着实现
在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...
- 个人对于angularjs依赖注入的理解
依赖注入(Dependency Injection,DI),作者认为本文中所有名词性的"依赖" 都可以理解为 "需要使用的资源". 对象或者函数只有以下3种获取 ...
- angularjs 依赖注入原理与实现
在用angular依赖注入时,感觉很好用,他的出现是 为了“削减计算机程序的耦合问题” ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个这么牛逼的功能.于是 ...
随机推荐
- js之序列化、eval和Date类用法
序列化 JSON.stringify() 将对象转换为字符串 JSON.parse() 将字符串转换为对象类型 示例 var jsonStr = '{"name":"le ...
- 数据库多对多关联表(Python&MySQL)
Python Python对MySQL数据库操作使用的是sqlalchemy这个ORM框架 #一本书可以有多个作者,一个作者又可以出版多本书 from sqlalchemy import Table, ...
- pycharm3.4 下svn 项目checkout&配置
pycharm 社区版: 3.4 1. checkout 项目 注意,之前配置好:设置里面的一些配置:(以下勾勾不要勾上) 2. checkout 项目之后,做以下操作: vcs ->enabl ...
- linux中shell截取字符串方法总结
截取字符串的方法一共有八种,主要为以下方法 shell中截取字符串的方法有很多中, ${expression}一共有9种使用方法. ${parameter:-word} ${parameter:=wo ...
- linux自动定时备份web程序和mysql数据库
前些天受朋友说linux定时备份不知道怎么搞,叫帮忙处理一下.由于这段时间正闲着,所以也就欣然答应.由于朋友对linux不懂也希望我将操作的过程记录下来,也就是越详细越好.所以写得比较$%^& ...
- Unity3D研究院之Prefab里面的Prefab关联问题(转)
转自http://www.xuanyusong.com/archives/3042 最近在做UI部分中遇到了这样的问题,就是Prefab里面预制了Prefab.可是在Unity里面一旦Prefab预制 ...
- 7.django之自定义分页记录
只是大概记录下步骤: 1.表结构: class UserProfile(models.Model): ''' 用户表 ''' user = models.OneToOneField(User,verb ...
- Spring配置数据源
Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0.可以在Spring配置文件中利用这两者中任何一个配置数据源. DBCP数据源 DBCP类包位于 ...
- codeforces 514B. Han Solo and Lazer Gun 解题报告
题目链接:http://codeforces.com/problemset/problem/514/B 题目意思:给出双头枪的位置(x0, y0),以及 n 个突击队成员的坐标.双头枪射击一次,可以把 ...
- linux下动态链接库解决方案(一)
1.c++无法直接调用用c写的动态链接库,如果调用的话可能需要用到一些交叉编译的知识: 2.在c++写的动态链接库无法被调用成功的反思: 在linux下,通常都是使用g++编译器("g++ ...