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

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

  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. python django 模板

    1 用两个大括号括起来的文字{{person_name}} 称为变量 2 被 大括号和面分号包围的文件({% if ordered_warranty %})是模板标签 3 过滤器是用管道符(|) 和U ...

  2. [部署]CentOS yum源

    安装yum源 一般的软件都会提供一个.rpm的软件包,使用rpm指令安装了这个包后会自动添加一个yum仓库源,之后用yum就可以安装该软件了. 安装rpm包 rpm -ivh http://repo. ...

  3. nginx如何设置访问跳转到一个固定页面

    方法一 server {    listen 80 ;    server_name  www.xxx.com xxx.com;      index   test.html  index.html ...

  4. Hadoop_YARN框架

    Hadoop学习笔记总结 01. YARN框架 1. 新一代的框架介绍 YARN的职能就是将资源调度和任务调度分开.资源管理器ResourceManager全局管理所有应用程序计算资源的分配,每一个j ...

  5. 自定义input[type="file"]的样式

    input[type="file"]的样式在各个浏览器中的表现不尽相同: 1. chrome: 2. firefox: 3. opera: 4. ie: 5. edge: 另外,当 ...

  6. LeetCode 1 Two Sum 解题报告

    LeetCode 1 Two Sum 解题报告 偶然间听见leetcode这个平台,这里面题量也不是很多200多题,打算平时有空在研究生期间就刷完,跟跟多的练习算法的人进行交流思想,一定的ACM算法积 ...

  7. codeforces 710E E. Generate a String(dp)

    题目链接: E. Generate a String time limit per test 2 seconds memory limit per test 512 megabytes input s ...

  8. Codeforces Round #258 E Devu and Flowers --容斥原理

    这题又是容斥原理,最近各种做容斥原理啊.当然,好像题解给的不是容斥原理的方法,而是用到Lucas定理好像.这里只讲容斥的做法. 题意:从n个容器中总共取s朵花出来,问有多少种情况.其中告诉你每个盒子中 ...

  9. Android Handler处理机制 ( 三 ) ——Handler,Message,Looper,MessageQueue

    在android中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知 handler基本使用: 在主线程中,使用handler很简单,new一个Handle ...

  10. 程序清单8-3 8-4 演示不同的exit值

    //http://blog.chinaunix.net/uid-24549279-id-71355.html /* ========================================== ...