最近在看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 就会尝试通过参数名推断依赖关系。
推断式注入声明