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源码,看看他到底是怎么实现的,我也想写个这么牛逼的功能.于是 ...
随机推荐
- 移动前端头部mete
原文链接:http://caibaojian.com/mobile-meta.html//code from http://caibaojian.com/mobile-meta.html<!DO ...
- Linux Ruijie登录命令
cd rjsupplicant chmod +x rjsupplicant.sh sudo ./rjsupplicant.sh -u 1550590×××× -p ××××× -d 1
- dtw算法
dtw路径与线性变换路径对比 转自:http://baike.baidu.com/link?url=z4gFUEplOyqpgboea6My0mZP ...
- Silverlight 中datagrid控件-- 通过设置数据虚拟化加速显示
定义依赖属性作为datagrid的数据源 protected static readonly DependencyProperty ViewLogsProperty = DependencyPrope ...
- AngularJS vs. jQuery
很多Web开发新手都会有这样的疑问“我应该使用什么开发框架呢,如何快速学会Web开发呢?”这个问题其实没有一个统一的正确答案,其中讨论最多的就是AngularJS和jQuery的差别.这两者的之间的比 ...
- 第七天 面向对象进阶与socket编程
1.静态方法(用得少)(解除某个函数跟类的关联,加了静态方法后,类便不能将类的参数传给静态方法函数了) class Dog(object): def __init__(self,name): @sta ...
- docker进入容器的方式
通过docker创建守护运行(在使用-d参数时)的容器时,容器启动后会进入后台.用户无法看到容器中的信息.某些时候如果需要进入容器进行操作,有多种方法,包括使用docker attach命令.dock ...
- zju3545
AC自动机+状态压缩DP 注意:相同的串可能出现多次,如果匹配成功则将各次权值加和. #include <cstdio> #include <queue> #include & ...
- 一些笔试题(C/C++)
1.there are two variables, don't use if.. else or ?: or switch or other judgement statements,find ou ...
- FFPlay-noConsole-ver-20160409-snapshot
ESC 退出 0 进度条开关 1 屏幕原始大小 2 屏幕1/2大小 3 屏幕1/3大小 4 屏幕1/4大小 S 下一帧 [ -2秒 ] +2秒 ; -1秒 ' +1秒 下一个帧 -> -5秒 F ...