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

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

  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. [转]Try Cloud Messaging for Android

    本文转自:https://developers.google.com/cloud-messaging/android/start

  2. [转]SQLServer 2008数据库查看死锁、堵塞的SQL语句

    本文转自:http://www.cnblogs.com/zhuque/archive/2012/11/08/2763343.html 死锁和堵塞一直是性能测试执行中关注的重点. 下面是我整理的监控sq ...

  3. Ubuntu 安装libusb

    执行以下指令 sudo apt-get install libusb-dev sudo apt-get install libusb-1.0-0-dev

  4. dipole antenna simulation by FEKO

    新建变量 建立模型 设置频率 馈电设置为wire port ,Edge 选中振子,从中心馈电. 设置输入信号 Mesh. run solver.在post feko中查看相关结果

  5. [原创]cin、cin.get()、cin.getline()、getline()、gets()、getchar()的区别

    这几个输入函数经常搞不清具体特点和用法,这里稍作总结 一.cin>> 1.最基本用法,输入一个变量值 2.输入字符串,遇“空格”.“TAB”.“回车”结束,比如输入“hello world ...

  6. 【实践】获取CKEditor的html文本、纯文本、被选中的内容及赋值

      <%=Html.TextAreaFor(Model => Model.WORK_INTRODUCTION)%> <script type="text/javasc ...

  7. 边工作边刷题:70天一遍leetcode: day 71-2

    One Edit Distance 要点:有两种解法要考虑:已知长度和未知长度(比如只给个iterator) 已知长度:最好不要用if/else在最外面分情况,而是loop在外,用err记录misma ...

  8. ES5和ES6中对于继承的实现方法

    在ES5继承的实现非常有趣的,由于没有传统面向对象类的概念,Javascript利用原型链的特性来实现继承,这其中有很多的属性指向和需要注意的地方. 原型链的特点和实现已经在之前的一篇整理说过了,就是 ...

  9. <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_acce

    在tomcat/conf/server.xml里的<host>标签下加上 <Valve className="org.apache.catalina.valves.Acce ...

  10. HTML5和css3的总结四

    HTML5的新东西总结四: 1>video和audio 声明方法(可以制作背景音乐) var oV/oA=new Video()/Audio(); oV/oA.src=''; oV/oA.pla ...