AngularJS之Dependency Injection(五)
前言
这一节我们来讲讲AngularJS中的依赖注入,在实际开发中Angular提供了具体的方法供我们去调用,但是一旦业务不能满足要求或者出现麻烦或者错误时导致无从下手,所以基于此我们有必要深入一点去了解内部的基本原理,这样我们才能将Angular玩弄于鼓掌之间。
话题
在讲述依赖注入时我们有必要讲一讲一个组件decorator(暂且叫做装饰者)。它也是创建服务的一个例子。decorator是一种设计模式,它能隔离修改及在不修改源码的前提下进行修改。在Angular中,它能够在服务、指令、过滤器使用之前被修改。
我们应该如何去使用使用装饰者,我们有两种方法来注册装饰者 $provide.decorator 和 module.decorator 这两种都有一个 $delegate ,这个被用来初始化服务、过滤器、指令。我们主要介绍第一种注册装饰者的方法
$provide.decorator
我们看看在Angular中日志服务是怎么来的。
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('$log', [
'$delegate',
function $logDecorator($delegate) {
var originalWarn = $delegate.warn;
$delegate.warn = function decoratedWarn(msg) {
msg = 'Decorated Warn: ' + msg;
originalWarn.apply($delegate, arguments);
};
return $delegate;
}
]);
}]);
一旦日志服务被初始化后,装饰者(decorator)就会被触发,decorator函数有一个注入到访问在装饰者中匹配所选择的服务的$delegate对象。$delegate是我们正在装饰的服务对象,提供装饰者返回的函数值将代替正在被装饰的服务、过滤器、指令。简单来讲,通过decorator我们能够在服务、过滤器或者指令使用之前进行适当的修改来满足我们所需,也就是说这是最原始实例化服务的方法,我们通过可以此方法来打补丁或者重写、修改等操作。在前面系列中我们讲了三种创建服务的方法,这节讲述怎样注册组件并且注入他们以此来解析依赖。
注册组件
通过$provide服务来注册例如下面服务以至于他们能被注入来满足依赖。这些组件是通过$injector而注册(下面会讲),当我们请求一个服务时,通过$injector来找到正确的service provider。初始化服务提供者并通过调用$get工厂函数来获取服务实例。通过$provide服务定义的许多服务方法被暴露在angular.module中。如下提供几个有用的通过$provide服务定义的方法。
| Name | Descriptions |
| constant(name, value) | 定义一个constant值 |
| decorator(name, service) | 定义一个服务decorator |
| factory(name, service) | 定义一个服务 |
| provider(name, service) | 定义一个服务 |
| service(name, provider) | 定义一个服务 |
| value(name, value) | 定义一个值服务 |
如上除了decorator未被暴露在angular.module中,原因猜想大概是:由于是最原始的初始化服务的方法,所以在大部分情况下我们都不会用到,除非在特定情况下要进行某一目的的特定修改我们才需要,所以未进行显式的暴露。在这里我们有必要来演示下。我们在Angular原始日志服务基础上添加一点信息来进行打印。
界面代码如下:
<head>
<meta charset="utf-8"/>
<title>Angular Injection</title>
<link href="../Content/bootstrap.min.css" rel="stylesheet"/>
<script src="../Scripts/angular.min.js"></script>
<script src="../DependencyInjection/Decoration.js"></script> </head>
<body ng-controller="indexController">
<div class="well">
<button class="btn btn-primary" ng-click="handleClick()">Click Me!</button>
</div>
</body>
</html>
脚本代码:
var testApp = angular.module('TestApp', []);
testApp.controller("indexController", function ($scope, $log) {
$scope.handleClick = function () {
$log.log("Button Clicked");
};
})
.config(function ($provide) {
$provide.decorator("$log", function ($delegate) {
$delegate.originalLog = $delegate.log;
$delegate.log = function (message) {
$delegate.originalLog("通过原始Decoration方法打印: " + message);
}
return $delegate;
});
});
通过上述脚本我们知道我们只是打印了【Button Clicked】,但是我们在使用日志服务之前添加了【通过原始Decoration方法打印】。我们看看效果:

管理组件
上述我们讲到通过$injector来管理组件,到底是怎么管理组件呢?当我们定义创建了组件时,我们需要用到时则要用$injector来获取我们定义的组件。它可以获取例如类型、调用方法、加载模块。下面我们来看看$injector服务有关方法:
| Name | Descriptions |
| annotate(fn) | 获取指定服务函数的参数,同时也包括那些与服务未通信的参数 |
| get(name) | 获取指定服务名称的服务对象 |
| has(name) | 判断指定服务名称的服务对象是否存在,若存在返回true,否则为false |
| invoke(fn, self, locals) | 调用指定函数, 使用指定函数的指定值以及非服务的参数值 |
$injector服务是AngularJS服务类库的核心,但是我们很少直接通过它来进行某些操作,但是我们有必要并且是有用的通过它来了解AngularJS的工作原理。
JS是一门动态而且牛逼的语言,但是还是缺少一点特性,比如在执行过程中动作的注释,而在C#中我们可以通过特性来看到,所以基于这种情况,我们来实现这种注释情况。
我们只需将上述控制器代码进行如下修改即可:
testApp.controller("indexController", function ($scope, $log, $injector) {
var counter = 0;
var logClick = function ($log, $exceptionHandler, message) {
if (counter == 0) {
$log.log(message);
counter++;
} else {
$exceptionHandler("Already clicked");
}
}
$scope.handleClick = function () {
var deps = $injector.annotate(logClick); //通过annotate方法来获取logClick函数其参数
for (var i = 0; i < deps.length; i++) {
console.log("Dependency: " + deps[i]);
}
};
})
获取我们logClick函数注入的服务以及参数,如下:

获取服务通过injector
我们来获取根元素的$injector服务,我们继续修改控制器代码,如下:
testApp.controller("indexController", function ($scope, $log, $rootElement) {
var counter = 0;
var logClick = function ($log, $exceptionHandler, message) {
if (counter == 0) {
$log.log(message);
counter++;
} else {
$exceptionHandler("不能再点击啦,点爆啦,哥们!");
}
}
$scope.handleClick = function () {
var localVars = { message: "第一次点击" };
$rootElement.injector().invoke(logClick, null, localVars);
};
})

$injector vs inject vs injector()
在我们注入组件后,需要获取该组件则可以通过$injector.get("serviceName")来获取所需服务,而inject同样也可以获取我们所需组件,如下:
app.controller('indexCtrl', indexCtrl);
indexCtrl.$inject = ['$scope','customService'];
function indexCtrl($scope, customService) {
.........
}
上述inject获取服务内部实质是通过$injector来获取(通过查资料得知,不太确定),通过$inject来获取服务更方便且简洁。上述还有一个injector方法,此方法用来获取元素所在模块的injector,通过 angular.element("id").injector() 来获取。讲到这里,顺便也讲讲scope方法,也是获取元素所在的作用域,通过 angular.element("id").scope() 来获取。
总结
今天我们就讲到这里,休息!
AngularJS之Dependency Injection(五)的更多相关文章
- AngularJs学习笔记--Dependency Injection(DI,依赖注入)
原版地址:http://code.angularjs.org/1.0.2/docs/guide/di 一.Dependency Injection(依赖注入) 依赖注入(DI)是一个软件设计模式,处理 ...
- Dependency Injection 筆記 (2)
续上集,接着要说明如何运用 DI 来让刚才的范例程序具备执行时期切换实现类型的能力. (本文摘自電子書<.NET 依賴注入>) 入门范例—DI 版本 为了让 AuthenticationS ...
- Dependency Injection 筆記 (1)
<.NET 依賴注入>連載 (1) 本文从一个基本的问题开始,点出软件需求变动的常态,以说明为什么我们需要学习「依赖注入」(dependency injection:简称 DI)来改善设计 ...
- asp.net core 系列之Dependency injection(依赖注入)
这篇文章主要讲解asp.net core 依赖注入的一些内容. ASP.NET Core支持依赖注入.这是一种在类和其依赖之间实现控制反转的一种技术(IOC). 一.依赖注入概述 1.原始的代码 依赖 ...
- Ninject学习(一) - Dependency Injection By Hand
大体上是把官网上的翻译下而已. http://www.ninject.90iogjkdcrorg/wiki.html Dependency Injection By Hand So what's Ni ...
- MVC Controller Dependency Injection for Beginners【翻译】
在codeproject看到一篇文章,群里的一个朋友要帮忙我翻译一下顺便贴出来,这篇文章适合新手,也算是对MEF的一个简单用法的介绍. Introduction In a simple stateme ...
- 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)
控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...
- [转载][翻译] IoC 容器和 Dependency Injection 模式
原文地址:Inversion of Control Containers and the Dependency Injection pattern 中文翻译版本是网上的PDF文档,发布在这里仅为方便查 ...
- Dependency Injection
Inversion of Control - Dependency Injection - Dependency Lookup loose coupling/maintainability/ late ...
随机推荐
- C语言中函数声明实现的位置
在学习C语言的时候我遇到了这么个事情,因为之前先学习的C#,在C#编译器中,函数的声明位置不会影响编译的结果,但是在C语言中却发生了错误 先看一段代码: #include <stdio.h> ...
- 日常工作bug总结
1.在使用jQuery的text()与val()使用时,如果按钮是<button></button>的形式使用text()写入时,在IE8下会出现延迟,即我在写定时器5秒倒计时 ...
- myBatis中 collection 或 association 联合查询 中column 传入多个参数值
下面是一个树形结构表自连接 联合查询 Demo <resultMap id="BaseResultMap" type="com.maidan.daas.entit ...
- 有哪些LabVIEW快捷键让你相见恨晚
前言 任何一门工具,当你使用它到极致的时候,往往都朝着这样子的两个方向发展 1. 具有鼠标操作功能的软件,他的使用的极致就是脱离鼠标,迈向键盘 2. 主要是键盘操作的,他的极致就是脚本自动化,或者说一 ...
- C#模拟http 发送post或get请求
/// <summary> /// 模拟HTTP提交表单并获取返回数据 /// POST /// </summary> /// <param name="Url ...
- poj3122-Pie(二分法+贪心思想)
一,题意: 有f+1个人(包括自己),n块披萨pie,给你每块pie的半径,要你公平的把尽可能多的pie分给每一个人 而且每个人得到的pie来自一个pie,不能拼凑,多余的边角丢掉.二,思路: 1,输 ...
- opecv获取图像轮廓
获取轮廓 #import <opencv2/opencv.hpp> #import <opencv2/imgcodecs/ios.h> #import <opencv2/ ...
- ASP.NET vNext 概述
兼容Mono的下一代云环境Web开发框架ASP.NET vNext 我们知道了ASP.NET vNext是一个全新的框架,是一个与时俱进的框架.这篇文章将深入讨论在整体架构更多的细节,文档参照 ASP ...
- EF遇到的一些问题
环境:EntityFramework 版本号:4.1.0.0 问题一:“数据读取器与指定的“.......”不兼容.某个类型为“...”的成员在同名的数据读取器中没有对应的列.”. 使用方式:rep. ...
- 初识ASP.NET Core 1.0
本文将对微软下一代ASP.NET框架做个概括性介绍,方便大家进一步熟悉该框架. 在介绍ASP.NET Core 1.0之前有必要澄清一些产品名称及版本号.ASP.NET Core1.0是微软下一代AS ...