AngularJS學習筆記之依賴注入

     最近在看AngularJS權威指南,因爲各類各樣的緣由(主要是由於我沒有money,好討厭的有木有......),因而我選擇了網上下載電子版的(由於它不要錢,哈哈...),字體也蠻清晰的,整體效果還不錯。可是,當我看到左上角的總頁碼的時候,479頁....479....479....俺的當心臟被擊穿了二分之一有木有啊,上半身都石化了有木有啊,那種特別想學可是看到頁碼又不想學的糾結的心情比和女友吵架了還複雜有木有啊,我日常看的電子書百位數都不大於3的好伐! 哎,原諒我吧,我應該多看幾本新華字典習慣習慣的...前端

     不過幸虧在看電子書以前,我已經稍微有點基礎了,以前看着視頻學習了一些,從雙向數據綁定到服務,而後到指令系統,都多多少少有些接觸。而且在一次web專選課結課做業當中,經過前端的AngularJS和後臺的NodeJS加Mongoose搭建了一個簡易學生班級管理系統。由於沒有錢,因此只能放在GitHub了,GitHub地址: 學生管理系統,歡迎來fork哈,下面進入正題...node

 

=======================================請叫我華麗的分割線=======================================git

     

一個對象一般有三種方式能夠得到對其依賴的控制權:
  (1) 在內部建立依賴;
  (2) 經過全局變量進行引用;
  (3) 在須要的地方經過參數進行傳遞。
     依賴注入是經過第三種方式實現的。其他兩種方式會帶來各類問題,例如污染全局做用域,使隔離變得異常困難等。依賴注入是一種設計模式,它能夠去除對依賴關係的硬編碼,從而能夠在運行時改變甚至移除依賴關係。angularjs

     在運行時修改依賴關係的能力對測試來說是很是理想的,由於它容許咱們建立一個隔離的環境,從而在測試環境可使用模擬的對象取代生產環境中的真實對象。github

     從功能上看,依賴注入會事先自動查找依賴關係,並將注入目標告知被依賴的資源,這樣就能夠在目標須要時當即將資源注入進去。web

     在編寫依賴於其餘對象或庫的組件時,咱們須要描述組件之間的依賴關係。在運行期,注入器會建立依賴的實例,並負責將它傳遞給依賴的消費者。設計模式

1 // 出自Angular文檔的優秀示例
2 function SomeClass(greeter) {
3 this.greeter = greeter;
4 }
5 SomeClass.prototype.greetName = function(name) {
6 this.greeter.greet(name);
7 };
8 //注意,示例代碼在全局做用域上建立了一個控制器,這並非一個好主意,這裏只是爲了方便演示。

     SomeClass 可以在運行時訪問到內部的 greeter ,但它並不關心如何得到對 greeter 的引用。爲了得到對 greeter 實例的引用, SomeClass 的建立者會負責構造其依賴關係並傳遞進去。
     基於以上緣由,AngularJS使用 $injetor (注入器服務)來管理依賴關係的查詢和實例化。事實上, $injetor 負責實例化AngularJS中全部的組件,包括應用的模塊、指令和控制器等。
     在運行時,任何模塊啓動時 $injetor 都會負責實例化,並將其須要的全部依賴傳遞進去。
     例以下面這段代碼。這是一個簡單的應用,聲明瞭一個模塊和一個控制器:數組

 1 angular.module('myApp', [])
 2 .factory('greeter', function() {
 3 return {
 4 greet: function(msg) {alert(msg);}
 5 }
 6 })
 7 .controller('MyController',
 8 function($scope, greeter) {
 9 $scope.sayHello = function() {
10 greeter.greet("Hello!");
11 };
12 });

    當AngularJS實例化這個模塊時,會查找 greeter 並天然而然地把對它的引用傳遞進去:app

1 <div ng-app="myApp">
2 <div ng-controller="MyController">
3 <button ng-click="sayHello()">Hello</button>
4 </div>
5 </div>

    而在內部,AngularJS的處理過程是下面這樣的:函數

1 // 使用注入器加載應用
2 var injector = angular.injector(['ng', 'myApp']);
3 // 經過注入器加載$controller服務
4 var $controller = injector.get('$controller');
5 // 加載控制器並傳入一個做用域,同AngularJS在運行時作的同樣
6 var scope = injector.get('$rootScope').$new();
7 var MyController = $controller('MyController', {$scope: scope});

    上面的代碼中並無說明是如何找到 greeter 的,可是它的確能正常工做,由於 $injector會負責爲咱們查找並加載它。
    AngularJS經過 annotate 函數,在實例化時從傳入的函數中把參數列表提取出來。在Chrome的開發者工具中輸入下面的代碼能夠查看這個函數:

 > injector.annotate(function($q, greeter) {})
 ["$q", "greeter"]

   在任何一個AngularJS的應用中,都有 $injector 在進行工做,不管咱們知道與否。當編寫控制器時,若是沒有使用 [] 標記或進行顯式的聲明, $injector 就會嘗試經過參數名推斷依賴關係。

 

   推斷式注入聲明  

   若是沒有明確的聲明,AngularJS會假定參數名稱就是依賴的名稱。所以,它會在內部調用函數對象的 toString() 方法,分析並提取出函數參數列表,而後經過 $injector 將這些參數注入進對象實例。注入的過程以下:

   injector.invoke(function($http, greeter) {});

   請注意,這個過程只適用於未通過壓縮和混淆的代碼,由於AngularJS須要原始未經壓縮的參數列表來進行解析。有了這個根據參數名稱進行推斷的過程,參數順序就沒有什麼重要的意義了,由於AngularJS會幫助咱們把屬性以正確的順序注入進去。

 

   式注入聲明 

   AngularJS提供了顯式的方法來明肯定義一個函數在被調用時須要用到的依賴關係。經過這種方法聲明依賴,即便在源代碼被壓縮、參數名稱發生改變的狀況下依然可以正常工做。能夠經過$inject 屬性來實現顯式注入聲明的功能。函數對象的 $inject 屬性是一個數組,數組元素的類型是字符串,它們的值就是須要被注入的服務的名稱。
   下面是示例代碼:

 1 var aControllerFactory =
 2 function aController($scope, greeter) {
 3 console.log("LOADED controller", greeter);
 4 // ……控制器
 5 };
 6 aControllerFactory.$inject = ['$scope', 'greeter']; // Greeter服務
 7 console.log("greeter service");
 8 }
 9 // 咱們應用的控制器
10 angular.module('myApp', [])
11 .controller('MyController', aControllerFactory)
12 .factory('greeter', greeterService);
13 // 獲取注入器並建立一個新的做用域
14 var injector = angular.injector(['ng', 'myApp']),
15 controller = injector.get('$controller'),
16 rootScope = injector.get('$rootScope'),
17 newScope = rootScope.$new();
18 // 調用控制器
19 controller('MyController', {$scope: newScope});

   對於這種聲明方式來說,參數順序是很是重要的,由於 $inject 數組元素的順序必須和注入參數的順序一一對應。這種聲明方式能夠在壓縮後的代碼中運行,由於聲明的相關信息已經和函數自己綁定在一塊兒了。

 

   行內注入聲明

   AngularJS提供的注入聲明的最後一種方式,是能夠隨時使用的行內注入聲明。這種方式實際上是一個語法糖,它同前面提到的經過 $inject 屬性進行注入聲明的原理是徹底同樣的,但容許咱們在函數定義時從行內將參數傳入。此外,它能夠避免在定義過程當中使用臨時變量。
   在定義一個AngularJS的對象時,行內聲明的方式容許咱們直接傳入一個參數數組而不是一個函數。數組的元素是字符串,它們表明的是能夠被注入到對象中的依賴的名字,最後一個參數就是依賴注入的目標函數對象自己。
   示例以下:

1 angular.module('myApp')
2 .controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
3 }]);

   因爲須要處理的是一個字符串組成的列表,行內注入聲明也能夠在壓縮後的代碼中正常運行。一般經過括號和聲明數組的 [] 符號來使用它。

相關文章
相關標籤/搜索