Angular的依賴注入

在Angular中創建一個對象時,需要依賴另一個對象,這是代碼層的一種依賴關系,當這種依賴被聲明后,Angular通過injector注入器將所依賴的對象進行注入操作

依賴注入介紹

依賴注入的原理

看下面的示例代碼:

<div ng-controller="MyController">
  <div class="{{cls}}">{{show}}</div>
  <button ng-click="onClick()">點我</button>
</div>
var myapp = angular.module('MyApp', []);
myapp.config(function($controllerProvider) {
  $controllerProvider.register('MyController', ['$scope', function($scope) {
    $scope.cls = '';
    $scope.onClick = function () {
      $scope.cls = 'show';
      $scope.show = '點擊后顯示的內容';
    }
  }])
})

看上面的代碼,與我們平時定義控制器的方式不一樣

myapp.controller('MyController', ['$scope', function($scope){
  // 控制器代碼
}])

在Angular中,通過模塊的config函數來聲明需要注入的依賴對象,而聲明的方式是通過調用provider服務。

但在Angular內部,控制器并不是由provider服務來創建的,而是由controllerProvider服務創建,在創建過程中,實際上是在config函數中調用controllerProvider服務的register方法,再調用injector注入器完成各個依賴對象的注入。

簡單依賴注入的示例

在Angular中,config函數的功能是為定義的模板對象注入依賴的各種服務。除了用于注冊控制器的controllerProvider服務外,還有一個$provider服務,其中它包含了如provider方法、factory方法、service方法和value方法,這些方法都可以通過服務創建一個自定義的依賴注入對象。

示例:

html:

<div ng-controller="myCtrl">
  <div class="{{cls}}">{{text}}</div>
  <button ng-click="onClick(1)">早上</button>
  <button ng-click="onClick(2)">上午</button>
  <button ng-click="onClick(3)">下午</button>
  <button ng-click="onClick(4)">晚上</button>
</div>
  var app = angular.module('myApp', []);
  app.config(function ($provide) {
    $provide.provider('myprovider', function () {
      this.$get = function () {
        return {
          val: function (name) {
            return name;
          }
        }
      }
    })
  });
  app.config(function ($provide) {
    $provide.factory('myfactory', function () {
      return {
        val: function (name) {
          return name;
        }
      }
    })
  });
  app.config(function ($provide) {
    $provide.value('myvalue', function (name) {
      return name;
    })
  });
  app.config(function ($provide) {
    $provide.service('myservice', function () {
      return {
        val: function (name) {
          return name;
        }
      }
    })
  });
  app.controller('myCtrl', ['$scope', 'myprovider', 'myfactory', 'myvalue', 'myservice',
  function ($scope, myprovider, myfactory, myvalue, myservice) {
    $scope.cls = '';
    $scope.onClick = function (t) {
      $scope.cls = 'show';
      switch (t) {
        case 1: $scope.text = myprovider.val('早上好'); break;
        case 2: $scope.text = myfactory.val('上午好'); break;
        case 3: $scope.text = myvalue('下午好'); break;
        case 4: $scope.text = myservice.val('晚上好'); break;
      }
    }
  }]);

依賴注入標記

每個Angular應用都是通過由注入器(injector)負責查找和創建依賴注入的服務,當注入器執行時,它需要一些標記,來判斷需要注入什么樣的依賴服務,而這些標記,就是依賴注入標記。

依賴注入標記根據聲明的方式,分為:

  • 推斷式注入
  • 標記式注入
  • 行內式注入

推斷式注入

推斷式注入是一種猜測式的注入,在沒有明確聲明的情況下,Angular認為參數名稱就是依賴注入的函數名,并在內部調用函數對象的toString方法,獲取對應的參數列表,然后通過注入器(injector)將這些參數注入到應用實例中,從而實現依賴注入。

示例:

html:

<div ng-controller="myCtrl">
  <input type="button" value="彈出對話框" ng-click="onClick('我是一個彈出對話框')">
</div>

javascript:

var app = angular.module('myApp', []);
  app.factory('myfactory', function ($window) {
    return {
      show: function (text) {
        $window.alert(text);
      }
    }
  });
  var myCtrl = function ($scope, myfactory) {
    $scope.onClick = function (msg) {
      myfactory.show(msg);
    }
  }
  app.controller('myCtrl', myCtrl);

標記式注入

標記式注入明確了一個函數在執行過程中需要依賴的各項服務,它可以直接調用$injector屬性來完成,它的屬性值是一個數組,數組元素是需要注入的各項服務的名稱,所以這種方式的注入順序很重要

示例:

html:

<div ng-controller="myCtrl">
  <div class="show">{{text}}</div>
  <input type="button" value="彈出" ng-click="onShow('我是一個彈出對話框')">
  <input type="button" value="顯示" ng-click="onWrite('今天天氣有點冷啊')">
</div>

javascript:

var app = angular.module('myApp', []);
  app.factory('$show', ['$window', function ($window) {
    return {
      show: function (text) {
        $window.alert(text);
      }
    }
  }]);
  app.factory('$write', function () {
    return {
      write: function (text) {
        return text;
      }
    }
  });

  var myCtrl = function ($scope, $show, $write) {
    $scope.onShow = function (msg) {
      $show.show(msg);
    }
    $scope.onWrite = function (msg) {
      $scope.text = $write.write(msg);
    }
  }
  app.controller('myCtrl', myCtrl);
  app.$inject = ['$scope', '$show', '$write'];

這種注入方式由于服務名和函數參數名在名稱和順序的一一對應關系,使得服務名和函數體綁定在一起,因此這種方式可以在壓縮或混淆后的代碼中執行。

行內式注入

所謂行內式注入,就是在構建一個Angular對象時,允許將一個字符型數組作為對象的參數,而不僅僅是一個函數。

在這個數組中,除最后一個必須是函數體外,其余都代表注入對象中的服務名,而他們的名稱和順序與最后一個函數的參數是一一對應的。

示例:

html:

<div ng-controller="myCtrl">
  <div class="show">{{text}}</div>
  <input type="button" value="求和" ng-click="onClick(5,10)">
</div>
var app = angular.module('myApp', []);
  app.factory('$sum', function () {
    return {
      add: function (m, n) {
        return m + n;
      }
    }
  });
  app.controller('myCtrl', ['$scope', '$sum', function ($scope, $sum) {
    $scope.onClick = function (m, n) {
      $scope.text = m + " + " + n + ' = ' + $sum.add(m, n);
    }
  }])

這種方法更簡潔,同樣也能在壓縮或混淆后的代碼中執行

$injector常用API

Angular中依賴注入離不開一個重要的對象--注入器($injector),整個Angular應用中的注入對象都由它負責定位和創建,它也有很多方法,如gethasinvoke

has和get方法

has方法的功能是根據傳入的名稱,從注冊的列表中查找對應的服務,如果找到返回true,否則返回false

injector.has(name)
  • injector為獲取的$injector對象
  • name為需要查找的服務名稱

最后返回一個布爾值

get方法返回指定名稱的服務實例,獲取到服務的實例對象后,就可以直接調用服務中的屬性和方法

injector.get(name)
  • injector為獲取的$injector對象
  • name為需要返回實例的服務名稱

執行代碼后,將返回一個服務實例

var app = angular.module('myApp', []);
  app.factory('$custom', function () {
    return {
      print: function (msg) {
        console.log(msg);
      }
    }
  });
  // 獲取injector對象
  var injector = angular.injector(['app', 'ng']);
  // 通過has方法判斷是否有$custom服務
  var has = injector.has('$custom');
  console.log(has);
  // 判斷如果存在$custom服務,則調用其方法在控制臺輸出任意字符
  if (has) {
    var custom = injector.get('$custom');
    custom.print('控制臺輸入任意的內容!');
  }
  app.controller('myCtrl', ['$scope', '$custom', function ($scope, $custom) {
    // ....
  }]);

invoke方法

invoke方法可以執行一個自定義的函數,除此之外,在執行函數時,還能傳遞變量給函數自身

injector.invoke(fn, [self], [locals])
  • injector為獲取的$injector對象
  • fn為需要執行的函數名稱
  • self是可選參數,它是一個對象,表示用于函數中的this變量
  • locals可選參數,也是一個對象,它能為函數中的變量名的傳遞提供方法支持
var myapp = angular.module('myApp', []);
  myapp.factory('$custom', function () {
    return {
      print: function (msg) {
        console.log(msg);
      }
    }
  });
  var injector = angular.injector(['myapp', 'ng']);
  var fun = function ($custom) {
    $custom.print('函數執行成功!');
  }
  injector.invoke(fun);
  myapp.controller('myCtrl', ['$scope', '$custom', function ($scope, $custom) {
    //...
  }])

依賴注入的應用場景

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 版本:Angular 5.0.0-alpha 依賴注入是重要的應用設計模式。它使用得非常廣泛,以至于幾乎每個人都稱...
    soojade閱讀 3,000評論 0 3
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 什么是依賴性注入? 依賴性注入( Dependency Injection )其實不是 Angular 獨有的概念...
    接灰的電子產品閱讀 4,068評論 3 18
  • AngularJS是什么?AngularJs(后面就簡稱ng了)是一個用于設計動態web應用的結構框架。首先,它是...
    200813閱讀 1,625評論 0 3
  • 菜鳥女編輯約稿有點難,因為起步就想玩過某虎某嗅,某3某6; 菜鳥女編輯約稿有點難,因為長的不像潘金蓮; 菜鳥女編輯...
    鉛化梅里閱讀 1,366評論 6 10