依赖注入是一种软件设计模式,用来处理代码的依赖关系。

一般来说有三种方法让函数获得它需要的依赖:

  1. 它的依赖是能被创建的,一般用new操作符就行。

  2. 能够通过全局变量查找依赖。

  3. 依赖能在需要时被导入。

前两种方式都不是很好,因为它们需要对依赖硬编码,使得修改依赖的时候变得困难。特别是在测试的时候不好办,因为对某个部分进行孤立的测试常常需要模拟它的依赖。

第三种方式是最好的,因为它不必在组件中去主动寻找和获取依赖,而是由外界将依赖传入。

举个例子:

function SomeClass(greeter) {
this.greeter = greeter
} SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}

上面的例子中SomeClass不关心去哪里获得叫greeter的依赖。这是我们想要的结果,但是这也同时把获取依赖的任务交给了负责创建SomeClass的代码。

每一个AngularJS应用都有一个注入器(injector)用来处理依赖的创建。注入器是一个负责查找和创建依赖的服务定位器。举个例子:

angular.module('myModule', []).
// 告诉注入器如何来创建这个greeter
// 注意这个greeter本身依赖'$window'
factory('greeter', function($window) {
// 这个方法,我们叫做工厂方法,它的作用是用来创建这个greeter服务
return {
greet: function(text) {
$window.alert(text);
}
};
})
// 在模块myModule中,创建一个新的注入器
// (这经常在angular启动时自动完成)
var injector = angular.injector('myModule');
// 从这个注入器中得到greeter这个服务
var greeter = injector.get('greeter');

通过请求依赖的方式解决了硬编码的问题,但是同样也意味着注入器需要在应用中传递,这违反了迪米特法则。我们通过使用下面这个例子中声明的方式来将依赖查找都给注入器来解决。

<!-- Given this HTML -->
<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
// And this controller definition
function MyController($scope, greeter) {
$scope.sayHello = function() {
greeter('Hello World');
};
}
//'ng-controller'指令做了以下事情
injector.instantiate(MyController);

注意,通过使用ng-controller来实例化控制器类,是的,控制器和注入器不再相关联,这是最好的结果。控制器中的代码可以简单的请求依赖而不必处理注入器。这种方式就没有破坏迪米特法则。

注入器怎么知道需要注入什么依赖呢?

注入器需要应用提供一些标记来表示自己需要的依赖。在关于AngularJS的某些API文档中你会看到函数都是被注入器调用的。注入器需要知道函数需要什么依赖。下面有三个等效的表示自己需要的依赖的方法。这些方法可以互相替换,并且是等效的。

(1)最简单的处理依赖的方法,就是假设函数的参数名就是依赖的名字

function MyController($scope, greeter) {
...
}

给出一个注入器,可以通过检查函数声明来获取函数名,从而知道需要依赖的函数。在上面的例子中,$scopegreeter是需要注入到函数中的依赖。

坦白的来讲,用了这种方法就不能使用JavaScript minifiers/obfuscators(一些用来缩短JS的类库)了,因为它们会改变变量名。

(2)要允许压缩类库重命名函数的参数,同时注入器又能正确处理依赖的话,函数需要使用$inject属性。这个属性是一个包含依赖的名称的数组。

var MyController = function(renamed$scope, renamedGreeter) {
...
}
MyController.$inject = ['$scope', 'greeter'];

注意$inject标记里的值和函数声明的参数是对应的。

这种方式适合用于控制器的声明,因为控制器有了明确的声明标记。

(3)有时候用$inject标记不是很方便,比如用来声明指令的时候。

使用$inject会导致代码膨胀:

var greeterFactory = function(renamed$window) {
...;
}; greeterFactory.$inject = ['$window']; someModule.factory('greeter', greeterFactory);

这种情况我们就推荐使用第三种方式:

someModule.factory('greeter', ['$window', function(renamed$window) {
...;
}]);

依赖注入在AngularJS中很普遍,一般用在控制器和工厂方法中。

控制器中的依赖注入:

控制器是负责应用行为的类。推荐的控制器声明方法如下:

var MyController = function(dep1, dep2) {
...
}
MyController.$inject = ['dep1', 'dep2']; MyController.prototype.aMethod = function() {
...
}

工厂方法的依赖注入:

工厂方法负责创建AngularJS中的大部分对象。比如指令,服务,过滤器。工厂方法一般在模块中使用,推荐的方法如下:

angular.module('myModule', []).
config(['depProvider', function(depProvider){
...
}]).
factory('serviceId', ['depService', function(depService) {
...
}]).
directive('directiveName', ['depService', function(depService) {
...
}]).
filter('filterName', ['depService', function(depService) {
...
}]).
run(['depService', function(depService) {
...
}]);

加油!

AngularJS开发指南10:AngularJS依赖注入的详解的更多相关文章

  1. AngularJS开发指南14:依赖注入

    推荐两种使用场景: 1.控制器中的依赖注入 控制器是负责应用行为的类.推荐的控制器声明方法如下: var MyController = function(dep1, dep2) { ... } MyC ...

  2. Spring 依赖注入方式详解

    平常的Java开发中,程序员在某个类中需要依赖其它类的方法. 通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. Spring提出了依赖注入的思想,即依赖类不由 ...

  3. Spring 依赖注入方式详解(四)

    IoC 简介 平常的Java开发中,程序员在某个类中需要依赖其它类的方法. 通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. Spring提出了依赖注入的思想 ...

  4. Unity依赖注入使用详解

    写在前面 构造器注入 Dependency属性注入 InjectionMethod方法注入 非泛型注入 标识键 ContainerControlledLifetimeManager单例 Unity注册 ...

  5. SpringDI四种依赖注入方式详解

    文章已托管到GitHub,大家可以去GitHub查看阅读,欢迎老板们前来Star!搜索关注微信公众号 [码出Offer] 领取各种学习资料! LOGO SpringDI(依赖注入) 一.DI概述 De ...

  6. .NET Core 中依赖注入框架详解 Autofac

    本文将通过演示一个Console应用程序和一个ASP.NET Core Web应用程序来说明依赖注入框架Autofac是如何使用的 Autofac相比.NET Core原生的注入方式提供了强大的功能, ...

  7. 依赖注入(IOC) 详解

    https://blog.csdn.net/qq_27093465/article/details/52547290 https://blog.csdn.net/qq_27093465/article ...

  8. 【转】angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  9. angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

随机推荐

  1. matlab ASCII 格式导入

    matlab ASCII 格式导入 可以用fprintf函数,来代替save函数啊比如现在我有一个变量a=[0.1223 345.4544]如果我想保存它的话,可以用下面的程序:fid = fopen ...

  2. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

    一.概述   定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的 ...

  3. 自定义listview的步骤

    1.定义一个实体类: public class Fruit { private String name; private int imageId; public Fruit(String name, ...

  4. git版本控制工具(二)----本地版本库的常用操作

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  5. AC日记——神奇的幻方 洛谷 P2615(大模拟)

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  6. Jenkins学习七:Jenkins的授权和访问控制

    默认的Jenkins不包含任何的安全检查,任何人可以修改Jenkins设置,job和启动build等.显然地在大规模的公司需要多个部门一起协调工作的时候,没有任何安全检查会带来很多的问题. 在系统管理 ...

  7. JMeter学习(三十二)属性和变量

    一.Jmeter中的属性: 1.JMeter属性统一定义在jmeter.properties文件中,我们可以在该文件中添加自定义的属性 2.JMeter属性在测试脚本的任何地方都是可见的(全局),通常 ...

  8. ES6严格模式use strict下的保留字

    implements interface let package private protected public static yield

  9. Android应用开发中如何使用隐藏API(转)

    一开始需要说明的是,Google之所以要将一些API隐藏(指加上@hide标记的public类.方法或常量)是有原因的.其中很大的原因就是Android系统本身还在不断的进化发展中.从1.0.1.1到 ...

  10. 【C#】ContextMenuStrip 右键菜单颜色设置

    有些时候自己想要修改ContexMenuStrip右键菜单的一些背景色之类的,该如何实现呢? 首先: ContextMenuStrip _context = new ContextMenuStrip( ...