AngularJS的依賴注入執行個體分析(使用module和injector),angularjsinjector
本文執行個體分析了AngularJS的依賴注入。分享給大家供大家參考,具體如下:
依賴注入(DI)的好處不再贅言,使用過spring架構的都知道。AngularJS作為前台js架構,也提供了對DI的支援,這是JavaScript/jQuery不具備的特性。angularjs中與DI相關有angular.module()、angular.injector()、 $injector、$provide。對於一個DI容器來說,必須具備3個要素:服務的註冊、依賴關係的聲明、對象的擷取。比如spring中,服務的註冊是通過xml設定檔的<bean>標籤或是註解@Repository、@Service、@Controller、@Component實現的;對象的擷取可以ApplicationContext.getBean()實現;依賴關係的聲明,即可以在xml檔案中配置,也可以使用@Resource等註解在Java代碼中聲明。在angular中,module和$provide相當於是服務的註冊;injector用來擷取對象(angular會自動完成依賴的注入);依賴關係的聲明在angular中有3種方式。下面從這3個方面,介紹下angular的DI。
1、angular.module()建立、擷取、註冊angular中的模組
The angular.module() is a global place for creating, registering and retrieving Angular modules.When passed two or more arguments, a new module is created. If passed only one argument, an existing module (the name passed as the first argument to module) is retrieved。
// 傳遞參數不止一個,代表建立模組;空數組代表該模組不依賴其他模組var createModule = angular.module("myModule", []);// 只有一個參數(模組名),代表擷取模組// 如果模組不存在,angular架構會拋異常var getModule = angular.module("myModule");// true,都是同一個模組alert(createModule == getModule);
該函數既可以建立新的模組,也可以擷取已有模組,是建立還是擷取,通過參數的個數來區分。
angular.module(name, [requires], [configFn]);
name:字串類型,代表模組的名稱;
requires:字串的數組,代表該模組依賴的其他模組列表,如果不依賴其他模組,用空數組即可;
configFn:用來對該模組進行一些配置。
現在我們知道如何建立、擷取模組了,那麼模組究竟是什麼呢?官方的Developer Guide上只有一句話:You can think of a module as a Container for the different parts of your app – controllers, services, filters, directives, etc.現在我還不太理解,大致就是說模組是一些功能的集合,如控制器、服務、過濾器、指令等子項目組成的整體。現在解釋不了,先遺留。
2、$provide和模組的關係
The $provide service has a number of methods for registering components with the $injector. Many of these functions are also exposed on angular.Module.
之前提到過:module和provide是用來註冊服務到injector中的。查看官方的API,可以看到$provide提供了provide()、constant()、value()、factory()、service()來建立各種不同性質的服務;angular.Module中也提供了這5個服務註冊方法。其實2者功能是完全一樣的,就是用來向DI容器註冊服務到injector中。
官方API下的auto有$provide 和 $injector,Implicit module which gets automatically added to each $injector.按照字面意思是說,每一個injector都有這2個隱含的服務。但1.2.25版本中,感覺沒有辦法擷取injector中的$provide。不知道這是為什麼?一般來說也不需要顯示使用這個服務,直接使用module中提供的API即可。
var injector = angular.injector();alert(injector.has("$provide"));//falsealert(injector.has("$injector"));//true
3、angular.injector()
使用angular.injector();也能擷取到注入器,但是沒有和模組綁定。這種做法是沒有意義的,相當於是你建立了一個空的DI容器,裡面都沒有服務別人怎麼用呢。正確的做法是,在建立注入器的時候,指定需要載入的模組。
// 建立myModule模組、註冊服務var myModule = angular.module('myModule', []);myModule.service('myService', function() { this.my = 0;});// 建立herModule模組、註冊服務var herModule = angular.module('herModule', []);herModule.service('herService', function() { this.her = 1;});// 載入了2個模組中的服務var injector = angular.injector(["myModule","herModule"]);alert(injector.get("myService").my);alert(injector.get("herService").her);
如果載入了多個模組,那麼通過返回的injector可以擷取到多個模組下的服務。這個例子中如果只載入了myMoudle,那麼得到的injector就不能訪問herMoudle下的服務。這裡特別需要注意下:angular.injector()可以調用多次,每次都返回建立的injector對象。
var injector1 = angular.injector(["myModule","herModule"]);var injector2 = angular.injector(["myModule","herModule"]);alert(injector1 == injector2);//false
4、angular中三種聲明依賴的方式
angular提供了3種擷取依賴的方式:inference、annotation、inline方式。
// 建立myModule模組、註冊服務var myModule = angular.module('myModule', []);myModule.service('myService', function() { this.my = 0;});// 擷取injectorvar injector = angular.injector(["myModule"]);// 第一種inferenceinjector.invoke(function(myService){alert(myService.my);});// 第二種annotationfunction explicit(serviceA) {alert(serviceA.my);};explicit.$inject = ['myService'];injector.invoke(explicit);// 第三種inlineinjector.invoke(['myService', function(serviceA){alert(serviceA.my);}]);
其中annotation和inline方式,對於函數參數名稱沒有要求,是推薦的做法;inference方式強制要求參數名稱和服務名稱一致,如果JS代碼經過壓縮或者混淆,那麼功能會出問題,不建議使用這種方式。