AngularJS开发指南10:AngularJS依赖注入的详解

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

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

  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) {
    ...
  }]);

加油!

时间: 2024-10-07 02:27:43

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

Unity依赖注入使用详解

Unity依赖注入使用详解 写在前面 构造器注入 Dependency属性注入 InjectionMethod方法注入 非泛型注入 标识键 ContainerControlledLifetimeManager单例 Unity注册配置问题 Unity的app.config节点配置 后记 关于 控制反转 (Inversion of Control)和 依赖注入 (Dependency Injection)大家网上可以找下相关概念,在 <小菜学习设计模式(五)—控制反转(Ioc)> 这篇文章中本人也

Spring 依赖注入方式详解

阅读目录 1.Set注入 2.构造器注入 3.静态工厂的方法注入 4.实例工厂的方法注入 平常的Java开发中,程序员在某个类中需要依赖其它类的方法. 通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. Spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过Spring容器帮我们new指定实例并且将实例注入到需要该对象的类中. 依赖注入的另一种说法是"控制反转".通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员.

AngularJS开发指南7:AngularJS本地化,国际化,以及兼容IE低版本浏览器

AngularJS本地化,国际化 国际化,简写为i18n,指的是使产品快速适应不同语言和文化. 本地化,简称l10n,是指使产品在特定文化和语言市场中可用. 对开发者来说,国际化一个应用意味着将所有的文字和其他因地区而异的数据从应用中抽离出来. 本地化意味着为这些抽离的数据和文字提供翻译和转变成本地的格式. 目前,AngularJS支持日期,数字和货币的国际化和本地化. 另外,AngularJS还通过ngPluralize指令支持本地多元化. 所有的AngularJS本地化组件都依赖于$loca

AngularJS开发指南:表达式

---恢复内容开始--- 表达式是类似Javascript的代码片段,通常在绑定中用到,写在双大括号中如{{表达式}}.表达式是用$parse方法来处理的. 下面是一些合法的AngularJS表达式 1+2 3*10 | currency user.name AngularJS表达式 与Javascript表达式的比较 你可能会认为AngularJS视图中的表达式就是Javascript表达式,这种认识不完全对,因为AngularJS不会用Javascript的eval()函数去执行表达式. 不

Angularjs开发指南

Angularjs开发指南:http://docs.ngnice.com/guide Angularjs中文网:http://www.apjs.net/

AngularJS学习--- AngularJS中XHR(AJAX)和依赖注入(DI) step5

前言:本文接前一篇文章,主要介绍什么是XHR,AJAX,DI,angularjs中如何使用XHR和DI. 1.切换工具目录 git checkout -f step-5 #切换分支 npm start #启动项目 2.什么是XHR和依赖注入(Dependency Injection)? 1)什么是XHR? XHR是XMLHttpRequest的简称,XMLHttpRequest 用于在后台与服务器交换数据,主要是为了实现在不重新加载整个网页的情况下,对网页的某部分进行更新.简单说,浏览器中URL

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

这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下 通常大家在使用ng中的指令的时候,用的链接函数最多的是link属性,下面这篇文章将告诉大家complie,pre-link,post-link的用法与区别. angularjs里的指令非常神奇,允许你创建非常语义化以及高度重用的组件,可以理解为web components的先驱者. 网上已经有很多介绍怎么使用指令

scons用户指南翻译(附gcc/g++参数详解)

scons用户指南 翻译 http://blog.csdn.net/andyelvis/article/category/948141 官网文档 http://www.scons.org/documentation.php ===================================== UNIX系统开发-gcc参数详解 [介绍] gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件[预处理器cpp] 2

Spring事务Transaction配置的五种注入方式详解

Spring事务Transaction配置的五种注入方式详解 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. ??? 总结如下: ??? Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. ???DataSou