AngularJS学习笔记之依赖注入详解


Posted in Javascript onMay 16, 2016

     最近在看AngularJS权威指南,由于各种各样的原因(主要是因为我没有money,好讨厌的有木有......AngularJS学习笔记之依赖注入详解),于是我选择了网上下载电子版的(因为它不要钱,哈哈...),字体也蛮清晰的,总体效果还不错。但是,当我看到左上角的总页码的时候,479页....479....479....俺的小心脏被击穿了二分之一有木有啊,上半身都石化了有木有啊,那种特别想学但是看到页码又不想学的纠结的心情比和女朋友吵架了还复杂有木有啊,我平常看的电子书百位数都不大于3的好伐! 哎,原谅我吧,我应该多看几本新华字典习惯习惯的...

不过幸好在看电子书之前,我已经稍微有点基础了,之前看着视频学习了一些,从双向数据绑定到服务,然后到指令系统,都多多少少有些接触。并且在一次web专选课结课作业当中,通过前端的AngularJS和后台的NodeJS加Mongoose搭建了一个简易学生班级管理系统。因为没有钱,所以只能放在GitHub了,GitHub地址: 学生管理系统,欢迎来fork哈,下面进入正题...

=======================================请叫我华丽的分割线=======================================

     

一个对象通常有三种方式可以获得对其依赖的控制权:

  (1) 在内部创建依赖;
  (2) 通过全局变量进行引用;
  (3) 在需要的地方通过参数进行传递。

依赖注入是通过第三种方式实现的。其余两种方式会带来各种问题,例如污染全局作用域,使隔离变得异常困难等。依赖注入是一种设计模式,它可以去除对依赖关系的硬编码,从而可以在运行时改变甚至移除依赖关系。

  在运行时修改依赖关系的能力对测试来讲是非常理想的,因为它允许我们创建一个隔离的环境,从而在测试环境可以使用模拟的对象取代生产环境中的真实对象。

 从功能上看,依赖注入会事先自动查找依赖关系,并将注入目标告知被依赖的资源,这样就可以在目标需要时立即将资源注入进去。

 在编写依赖于其他对象或库的组件时,我们需要描述组件之间的依赖关系。在运行期,注入器会创建依赖的实例,并负责将它传递给依赖的消费者。

// 出自Angular文档的优秀示例
function SomeClass(greeter) {
this.greeter = greeter;
}
SomeClass.prototype.greetName = function(name) {
this.greeter.greet(name);
};
//注意,示例代码在全局作用域上创建了一个控制器,这并不是一个好主意,这里只是为了方便演示。

SomeClass 能够在运行时访问到内部的 greeter ,但它并不关心如何获得对 greeter 的引用。为了获得对 greeter 实例的引用, SomeClass 的创建者会负责构造其依赖关系并传递进去。

基于以上原因,AngularJS使用 $injetor (注入器服务)来管理依赖关系的查询和实例化。事实上, $injetor 负责实例化AngularJS中所有的组件,包括应用的模块、指令和控制器等。

在运行时,任何模块启动时 $injetor 都会负责实例化,并将其需要的所有依赖传递进去。

例如下面这段代码。这是一个简单的应用,声明了一个模块和一个控制器:

angular.module('myApp', [])
.factory('greeter', function() {
return {
greet: function(msg) {alert(msg);}
}
})
.controller('MyController',
function($scope, greeter) {
$scope.sayHello = function() {
greeter.greet("Hello!");
};
});

当AngularJS实例化这个模块时,会查找 greeter 并自然而然地把对它的引用传递进去:

<div ng-app="myApp">
<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
</div>

而在内部,AngularJS的处理过程是下面这样的:

// 使用注入器加载应用
var injector = angular.injector(['ng', 'myApp']);
// 通过注入器加载$controller服务
var $controller = injector.get('$controller');
// 加载控制器并传入一个作用域,同AngularJS在运行时做的一样
var scope = injector.get('$rootScope').$new();
var MyController = $controller('MyController', {$scope: scope});

上面的代码中并没有说明是如何找到 greeter 的,但是它的确能正常工作,因为 $injector会负责为我们查找并加载它。

AngularJS通过 annotate 函数,在实例化时从传入的函数中把参数列表提取出来。在Chrome的开发者工具中输入下面的代码可以查看这个函数:

> injector.annotate(function($q, greeter) {})
 ["$q", "greeter"]

在任何一个AngularJS的应用中,都有 $injector 在进行工作,无论我们知道与否。当编写控制器时,如果没有使用 [] 标记或进行显式的声明, $injector 就会尝试通过参数名推断依赖关系。

推断式注入声明 

如果没有明确的声明,AngularJS会假定参数名称就是依赖的名称。因此,它会在内部调用函数对象的 toString() 方法,分析并提取出函数参数列表,然后通过 $injector 将这些参数注入进对象实例。注入的过程如下:

injector.invoke(function($http, greeter) {});

请注意,这个过程只适用于未经过压缩和混淆的代码,因为AngularJS需要原始未经压缩的参数列表来进行解析。有了这个根据参数名称进行推断的过程,参数顺序就没有什么重要的意义了,因为AngularJS会帮助我们把属性以正确的顺序注入进去。

显式注入声明

AngularJS提供了显式的方法来明确定义一个函数在被调用时需要用到的依赖关系。通过这种方法声明依赖,即使在源代码被压缩、参数名称发生改变的情况下依然能够正常工作。可以通过$inject 属性来实现显式注入声明的功能。函数对象的 $inject 属性是一个数组,数组元素的类型是字符串,它们的值就是需要被注入的服务的名称。

下面是示例代码:

var aControllerFactory =
function aController($scope, greeter) {
console.log("LOADED controller", greeter);
// ……控制器
};
aControllerFactory.$inject = ['$scope', 'greeter']; // Greeter服务
console.log("greeter service");
}
// 我们应用的控制器
angular.module('myApp', [])
.controller('MyController', aControllerFactory)
.factory('greeter', greeterService);
// 获取注入器并创建一个新的作用域
var injector = angular.injector(['ng', 'myApp']),
controller = injector.get('$controller'),
rootScope = injector.get('$rootScope'),
newScope = rootScope.$new();
// 调用控制器
controller('MyController', {$scope: newScope});

对于这种声明方式来讲,参数顺序是非常重要的,因为 $inject 数组元素的顺序必须和注入参数的顺序一一对应。这种声明方式可以在压缩后的代码中运行,因为声明的相关信息已经和函数本身绑定在一起了。

行内注入声明

AngularJS提供的注入声明的最后一种方式,是可以随时使用的行内注入声明。这种方式其实是一个语法糖,它同前面提到的通过 $inject 属性进行注入声明的原理是完全一样的,但允许我们在函数定义时从行内将参数传入。此外,它可以避免在定义过程中使用临时变量。

在定义一个AngularJS的对象时,行内声明的方式允许我们直接传入一个参数数组而不是一个函数。数组的元素是字符串,它们代表的是可以被注入到对象中的依赖的名字,最后一个参数就是依赖注入的目标函数对象本身。

示例如下:

angular.module('myApp')
.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
}]);

由于需要处理的是一个字符串组成的列表,行内注入声明也可以在压缩后的代码中正常运行。通常通过括号和声明数组的 [] 符号来使用它。

以上这篇AngularJS 依赖注入就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js获取某月的最后一天日期的简单实例
Jun 22 Javascript
类似php的js数组的in_array函数自定义方法
Dec 27 Javascript
使用js实现的简单拖拽效果
Mar 18 Javascript
高性能JavaScript DOM编程(1)
Aug 11 Javascript
快速掌握Node.js模块封装及使用
Mar 21 Javascript
JavaScript实现时间倒计时跳转(推荐)
Jun 28 Javascript
Vue自定义指令实现checkbox全选功能的方法
Feb 28 Javascript
js数据类型检测总结
Aug 05 Javascript
Vue开发之封装分页组件与使用示例
Apr 25 Javascript
ElementUI中el-tree节点的操作的实现
Feb 27 Javascript
Element MessageBox弹框的具体使用
Jul 27 Javascript
浅谈JavaScript节流和防抖函数
Aug 25 Javascript
javascript表单事件处理方法详解
May 15 #Javascript
基于jquery实现ajax无刷新评论
Aug 19 #Javascript
JavaScript代码性能优化总结篇
May 15 #Javascript
window.onload绑定多个事件的两种解决方案
May 15 #Javascript
js仿淘宝和百度文库的评分功能
May 15 #Javascript
RequireJS使用注意细节
May 15 #Javascript
JSON 的正确用法探讨:Pyhong、MongoDB、JavaScript与Ajax
May 15 #Javascript
You might like
PHP CKEditor 上传图片实现代码
2009/11/06 PHP
PHP教程之PHP中shell脚本的使用方法分享
2012/02/23 PHP
PHP调用VC编写的COM组件实例
2014/03/29 PHP
php的mail函数发送UTF-8编码中文邮件时标题乱码的解决办法
2015/10/20 PHP
WordPress中限制非管理员用户在文章后只能评论一次
2015/12/31 PHP
laravel5.5添加echarts实现画图功能的方法
2019/10/09 PHP
Javascript中的数学函数
2007/04/04 Javascript
用js来解决ajax读取页面乱码
2010/11/28 Javascript
jQuery如何防止这种冒泡事件发生
2015/02/27 Javascript
jQuery validate+artdialog+jquery form实现弹出表单思路详解
2016/04/18 Javascript
jqGrid用法汇总(全经典)
2016/06/28 Javascript
原生javascript 学习之js变量全面了解
2016/07/14 Javascript
AngularJS动态加载模块和依赖的方法分析
2016/11/08 Javascript
详解vue.js之props传递参数
2017/12/12 Javascript
微信小程序实现定位及到指定位置导航的示例代码
2019/08/20 Javascript
jquery+ajax实现异步上传文件显示进度条
2020/08/17 jQuery
Javascript 模拟mvc实现点餐程序案例详解
2020/12/24 Javascript
[01:05:40]VG vs Newbee 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python如何拆分含有多种分隔符的字符串
2018/03/20 Python
浅谈Python 多进程默认不能共享全局变量的问题
2019/01/11 Python
python自动发送测试报告邮件功能的实现
2019/01/22 Python
pytz格式化北京时间多出6分钟问题的解决方法
2019/06/21 Python
python xlwt如何设置单元格的自定义背景颜色
2019/09/03 Python
Python + Flask 实现简单的验证码系统
2019/10/01 Python
Python 中list ,set,dict的大规模查找效率对比详解
2019/10/11 Python
python提取xml里面的链接源码详解
2019/10/15 Python
Python装饰器使用你可能不知道的几种姿势
2019/10/25 Python
浅析Python 条件控制语句
2020/07/15 Python
Python Pandas数据分析工具用法实例
2020/11/05 Python
基于html5绘制圆形多角图案
2016/04/21 HTML / CSS
德国箱包网上商店:koffer24.de
2016/07/27 全球购物
公务员处分决定书
2015/06/25 职场文书
正规欠条模板
2015/07/03 职场文书
2015年乡镇食品安全工作总结
2015/10/22 职场文书
Python 把两层列表展开平铺成一层(5种实现方式)
2021/04/07 Python
Oracle 多表查询基本语法实例
2022/04/18 Oracle