AngularJS学习笔记之依赖注入
最近在看AngularJS权威指南,由于各种各样的原因(主要是因为我没有money,好讨厌的有木有......),于是我选择了网上下载电子版的(因为它不要钱,哈哈...),字体也蛮清晰的,总体效果还不错。但是,当我看到左上角的总页码的时候,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学习笔记之依赖注入的更多相关文章
- SpringMVC:学习笔记(11)——依赖注入与@Autowired
SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...
- Spring.NET学习笔记6——依赖注入(应用篇)
1. 谈到高级语言编程,我们就会联想到设计模式:谈到设计模式,我们就会说道怎么样解耦合.而Spring.NET的IoC容器其中的一种用途就是解耦合,其最经典的应用就是:依赖注入(Dependeny I ...
- Unity学习笔记(4):依赖注入
Unity具体实现依赖注入包含构造函数注入.属性注入.方法注入,所谓注入相当赋值,下面一个一个来介绍 1:构造函数注入 1.1当类有多个构造函数时,可以通过InjectionConstructor特性 ...
- angular2 学习笔记 ( DI 依赖注入 )
refer : http://blog.thoughtram.io/angular/2016/09/15/angular-2-final-is-out.html ( search Dependency ...
- Angular4.0从入门到实战打造在线竞拍网站学习笔记之三--依赖注入
Angular4.0基础知识之组件 Angular4.0基础知识之路由 依赖注入(Dependency Injection) 正常情况下,我们写的代码应该是这样子的: let product = ne ...
- Asp.net core 学习笔记 ( DI 依赖注入 )
比起 Angular 的依赖注入, core 的相对简单许多, 容易明白 所有 provider 都在 startup 里配置. public void ConfigureServices(IServ ...
- [学习笔记]Spring依赖注入
依赖: 典型的企业应用程序不可能由单个对象(在spring中,也可称之bean)组成,再简单的应用也是由几个对象相互配合工作的,这一章主要介绍bean的定义以及bean之间的相互协作. 依赖注入: s ...
- Spring学习笔记——Spring依赖注入原理分析
我们知道Spring的依赖注入有四种方式,各自是get/set方法注入.构造器注入.静态工厂方法注入.实例工厂方法注入 以下我们先分析下这几种注入方式 1.get/set方法注入 public cla ...
- Spring学习笔记1—依赖注入(构造器注入、set注入和注解注入)
什么是依赖注入 在以前的java开发中,某个类中需要依赖其它类的方法时,通常是new一个依赖类再调用类实例的方法,这种方法耦合度太高并且不容易测试,spring提出了依赖注入的思想,即依赖类不由程序员 ...
随机推荐
- Android基于mAppWidget实现手绘地图(四)--如何附加javadoc
如何把javadoc添加到代码库中? How to attach javadoc to the library? 项目属性——>Java Build Path——>Libraries.选择 ...
- Tools - VirtualBox
为CentOS虚拟机安装增强功能 启动CentOS虚拟机,点击"菜单 -> 设备 -> 安装增强功能". vboxadd的映像文件将会被挂载到虚拟机,在桌面也可以看到, ...
- 优秀工具推荐:超实用的 CSS 库,样板和框架
当启动一个新的项目,使用 CSS 框架或样板,可以帮助您节省大量的时间.在这篇文章中,我编译整理了我最喜欢的 CSS 样板,框架和库,帮助你在建立网站或应用程序时更加高效. 您可能感兴趣的相关文章 精 ...
- S Gallery – 很有特色的响应式 jQuery 相册插件
S Gallery 是一款响应式的 jQuery 相册插件.使用了 HTML5 全屏 API 以及 CSS3 动画 和 CSS3 转换,所以只能在支持这些功能的浏览器中使用. 这款插件它有一个特色功能 ...
- 只用一行代码让你的ASP.NET MVC 跑起来
只用一行代码让你的ASP.NET MVC 跑起来 MVC框架一直是企业开发绕不过去的东西,先是JavaEE的 Structs, 然后是 Spring MVC, 再到我们今天要讨论的ASP.NET MV ...
- Windows Azure Cloud Service (12) PaaS之Web Role, Worker Role, Azure Storage Queue(下)
<Windows Azure Platform 系列文章目录> 本章DEMO部分源代码,请在这里下载. 在上一章中,笔者介绍了我们可以使用Azure PaaS的Web Role和Worke ...
- [SDK2.2]Windows Azure Virtual Network (3) 创建AD Server并添加至Virtual Network
<Windows Azure Platform 系列文章目录> 在之前的文章中,笔者已经向大家介绍了如何创建一个简单的Azure Virtual Network. 本章我将创建一台域服务器 ...
- java设计模式(四)--单例模式
Singleton最熟悉不过了,下面学习单例模式.转载:http://zz563143188.iteye.com/blog/1847029 单例对象(Singleton)是一种常用的设计模式.在Jav ...
- 微信开发之.Net
撸主是一个新手,最近几天在研究微信服务号交互,上网搜了搜C#的代码,再结合自己的习惯,下面把代码解析一下,其中有些代码非本人原创. 首先,你要有个公众服务号,只有服务号才可以自定义菜单,没有条件的可以 ...
- [Java 基础]运算符和表达式
Java运算符 (1)赋值操作符 赋值操作符(=)表示:取右边的值(即右值),把它复制给左边(即左值). 右值可以是任意的常量.变量或表达式(只要可以生成一个值). 左值必须是一个明确的.已命名的变量 ...