天天看點

對AngularJs中依賴注入的了解和使用方法

Angular中的依賴注入

一:什麼是依賴注入?

  依賴注入是一種軟體設計模式,在這種模式下,一個或更多的依賴被注入到一個獨立的對象中,然後成為該對象的一部分。該模式分離了用戶端依賴本身行為的建立,使得程式設計變得松耦合,并遵循了依賴反轉和單一職責原則。與服務定位器模式形成直接對比的是,它允許用戶端了解用戶端如何使用該系統找到依賴。

AngularJS 提供很好的依賴注入機制。以下5個核心元件用來作為依賴注入,即他們都可以向控制器中注入值或者建立服務:

1.value

2.factory

3.service

4.provider

5.constant

二:詳解每個組建地用法?

  • value():value 是一個簡單的 javascript 對象,用于向控制器傳遞值(配置階段):
<div ng-app="mainApp" ng-controller="CalcController">
    .........
</div>
<script type="text/javascript">
    // 定義一個子產品  
    var mainApp = angular.module("mainApp", []);  
    // 建立 value 對象 "defaultInput" 并傳遞資料  
    mainApp.value("defaultInput", );  
    // 将 "defaultInput" 注入到控制器  
    mainApp.controller('CalcController', function($scope, defaultInput) {  
        $scope.number = defaultInput;  
        console.log(defaultInput)
    }); 
</script>
           
  • factory():factory傳回一個對象,隻需要建立一個對象,為它添加屬性,然後傳回這個對象,在控制器中注入該factory,即可使用它的所有屬性。
//4.factory 是一個函數用于傳回值。在 service 和 controller 需要時建立。通常我們使用 factory 函數來計算或傳回值。
        mainApp.factory('MathService', function() {
            var factory = {};
            factory.multiply = function(a, b) {
                return a * b
            }
                return factory;
        });
           

Angular裡面建立服務的一個方式是使用factory()方法,factory()讓我們通過傳回一個包含服務方法和資料的對象來定義一個服務。在建立的服務方法裡我們可以注入其他服務,比如&http;

angular.module('myApp.services').factory('User', function($http) {     
                var backendUrl = "http://localhost:3000";
                var service = {                                             
                    user: {},
                    setName: function(newName) {
                        service.user['name'] = newName;
                    },
                    setEmail: function(newEmail) {
                        service.user['email'] = newEmail;
                    },
                    save: function() {
                        return $http.post(backendUrl + '/users', {
                            user: service.user
                        });
                    }
                };
                return service;
            });
           
  • service() service()通過構造函數的方式讓我們建立service,我們當然可以使用原型模式替代javaScript原始的對象來定義service。service 類似于一個構造器, 通過 new 關鍵字執行個體化對象,将一些屬性和方法直接添加到 this 上,在建立 service 對象時, this 會被作為傳回值傳回,和factory()方法一樣我們也可以在函數的定義裡面看到服務的注入。
app.service('hexafy', function() {
    this.myFunc = function (x) {
        return x.toString();
    }
});
app.controller('myCtrl', function($scope, hexafy) {
  $scope.hex = hexafy.myFunc();
});
           
  • provider() 所有的服務工廠都是由 provide服務建立的, provide服務負責在運作時初始化這些提供者,提供者是具有 get()方法的對象, injector通過調用 get方法建立服務執行個體。 provider提供了數個不同的API用于建立服務。每個方法都有各自的特殊用途。例如:
// 使用 provider 建立一個 MathService服務,用于定義一個方法用于計算兩數乘積
mainApp.config(function($provide) {
   $provide.provider('MathService', function() {
      this.$get = function() {
         var obj= {};  
         obj.multiply = function(a, b) {
            return a * b; 
         }
         return obj;
      };
   });
});
           

如果不了解,請耐心往下看:

  從技術上說,當我們假定傳入的函數就是$get()時,factory()函數就是用provider()方法注冊服務的簡略形式。(實際上Provider 中提供了一個 factory 方法 get(),它用于傳回 value/service/factory。)

下面兩種方法的作用完全一樣,并且會建立同一個服務。

angular.module('myApp').factory('myService',function(){
    var obj  = {'username' : 'bangbang'};
    return obj;
})
           

這與上面工廠的用法等價

angular.module('myApp').provider('myService',{
    $get : function(){
        var obj = {'username' : 'bangbang'};
        return obj;
    }
})
           

是否可以一直使用factory()方法來代替provider()呢?

答案取決于是否需要用AngularJs的.config()函數來對.provider()方法傳回的服務進行額外的擴充配置。同其他建立服務的方法不同,config()方法可以被注入特殊的參數。比如,我們希望在應用啟動前配置girhubService的URL:

var app = angular.module('myApp',[]);   
        //使用provider注冊該服務
        app.provider('githubService',function(){
            //預設的,私有狀态
            var githubUrl = 'https://github.com';
            return {
                setGithubUrl  : function(url){
                    //通過.config改變預設屬性
                    if(url){
                        githubUrl = url;
                    }
                },
                $get : function($http){
                    self = this;
                    return $http({method : 'get', url:'datas.json'});
                }
            }
        })

        app.controller('myCtrl',function($scope,githubService){
            console.log(githubService)
        })
           

  通過使用provider()方法,可以在多個應用使用同一個服務時候獲得更強的擴充,特别是在不同應用或開源社群之間共享服務時。

  在上面例子中,provider()方法在服務githubService後生成了一個新的提供者,githubServiceProvider即(服務名+Provider),該提供者即gitbubServiceProvider可以被注入到config()函數中。

angular.modele('myApp',[]).config(function(gitbubServiceProvider){
    githubServiceProvider.setGithubUrl("[email protected]");
})
           

如果希望在config()函數中可以對服務進行配置,必須用provider()來定義服務。

provider()方法為服務注冊提供者,可以接受兩個參數:

第一個參數:name(字元串):name參數在providerCache中是注冊的名字,name+provider會成為服務的提供者。同時name也是服務執行個體的名字。例如:如果我們定義了githubService,那它的提供者是githubServiceProvider。

第二個參數:aProvider(對象/函數/數組):aProvider可以是多種形式,

  • 如果aProvider是函數,那麼它會通過依賴注入被調用,并且負責通過$get方法傳回一對象;
  • 如果aProvider是數組,他會被當做一個帶有行内依賴注入聲明的函數來處理。數組的最後的一個元素應該是函數,可以傳回帶有一個$get方法的對象;
  • 如果aProvider是對象它應該帶有$get方法。

    provider()函數傳回一個已經注冊的提供者執行個體。

    直接使用provider()API是最原始的建立服務的方法:

//在子產品對象上直接建立provider的例子
        var app = angular.module('myApp',[]);
        app.provider("myService",{
            favoriteColor : null,
            setFavoriteColor : function(newColor){
                this.favoriteColor = newColor;
            },
            //$get函數可以接受injectables
            $get : function($http){
                return{
                    'name' : 'bangbang',
                    getFavoriteColor : function(){
                        return this.favoriteColor || 'unknown';
                    }
                }
            }
        })
        app.controller('myCtrl',function($scope,myService){
            console.log(myService)
            myService.getFavoriteColor('white');
        })
           

用這個方法建立服務,必須傳回一個定義有$get()函數的對象,否則會導緻錯誤。provider()是非常強大的,可以讓我們在不同的應用中共享服務。

  • constant() constant可以将一個已經存在的變量值注冊為服務,并将其注入到應用的其他部分當中。例如,假設我們需要給後端服務一個apiKey,可以用constant()将其作為常量儲存下來。constant()函數接受兩個參數:name(字元串),需要注冊常量的名字,value(常量)需要注冊常量的值或者對象。執行個體如下:
var app = angular.module('myApp',[]);
        app.constant('names',['bangbang','qiqi','niuniu']).controller('myCtrl',function($scope,names){
            console.log(names); //["bangbang", "qiqi", "niuniu"]
        })
           
  • 何時使用value()和constant()

      value()方法和constant()方法之間最重要的差別是,常量可以注入到配置函數中,但是值不行。通常情況下,可以通過value()來注冊服務對象或函數,用constant()來配置資料。

var app = angular.module('myApp',[]);
        app.constant('number','22').config(function(number){
            //在這裡number将被指派為22
            console.log(number)
        }).value('name','bangbang').config(function(name){
            console.log(name);      //這将抛出一個錯誤,因為,在config()函數内部無法通路這個值
        })
           

參考文章和書籍:

  • Angular Js權威教程
  • Angular Js菜鳥教程
  • AngularJS中的Provider們:Service和Factory等的差別
  • 跟我學AngularJs:Service、Factory、Provider依賴注入使用與差別
  • AngularJS中service,factory,provider的差別
  • 關于AngularJS中的DI

繼續閱讀