日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

理解AngularJS中的依赖注入

發(fā)布時間:2025/7/14 javascript 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理解AngularJS中的依赖注入 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者 CraftsCoder?

冷月無聲 -?博客頻道 - CSDN.NET

??http://blog.csdn.net/jaytalent/article/details/50986402

?

本文結(jié)合一些資料,談談AngularJS的依賴注入機制。主要參考資料有:

1. AngularJS官方文檔:https://docs.angularjs.org/guide/di

2. Github文章:https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection

3. 專著:Pro AngularJS

4. AngularJS 源代碼

一、關于依賴注入

依賴注入式AngularJS的重要特性之一,有關概念和定義參考維基百科。依賴注入簡化了Angular解析模塊/組件之間依賴的過程。通常一個組件要獲得它的依賴,有三種方式:

?

  • 直接創(chuàng)建出依賴,如使用new操作符
  • 能夠查找到依賴,如引用全局變量
  • 在需要的地方傳入依賴
  • 第三種的優(yōu)勢在于組件省去了定義/定位依賴的過程,也使得依賴的耦合度降低,可擴展性更強。依賴注入主要有兩種形式(看這里):setter注入和constructor注入。前者的代表是Spring框架的setter方式,AngularJS則使用的是constructor注入。這里簡單說一下二者的區(qū)別,setter注入顧名思義,首先使用一個無參的默認構(gòu)造器構(gòu)造對象,然后使用setter方法將依賴注入到新對象中。這種方式的一個缺陷是在編譯時并不知道對象之間的依賴關系,依賴解析由某種框架在運行時完成。如果在配置依賴時有遺漏,則在運行時會報空引用錯誤。對于constructor注入,在構(gòu)造對象時,將依賴的組件以參數(shù)形式傳入構(gòu)造器,傳入組件所依賴的組件以相同的方式構(gòu)造,依此類推,確保依賴鏈條最頂端的組件首先構(gòu)造,一直到當前需要注入的對象構(gòu)造完畢。該方式避免了依賴的遺漏。 二、AngularJS中的依賴注入 Angular的injector子系統(tǒng)負責創(chuàng)建組件,解析依賴,并將其按需提供給其他組件。每個Angular應用都有一個injector。Angular在應用的啟動階段(bootstrap,參見前面的文章)會創(chuàng)建一個injector: [javascript]?view plaincopy
  • var?injector?=?angular.injector(['ng',?'myApp']);??
  • injector方法的數(shù)組參數(shù)定義了可以提供依賴組件的模塊,一般會提供模塊'ng'和應用首先加載的模塊'myApp'。查看源碼發(fā)現(xiàn),injector方法實際上實現(xiàn)為createInjector方法,由bootstrap方法調(diào)用。createInjector內(nèi)部調(diào)用createInternalInjector方法返回真正的injector對象,返回結(jié)果如下: [javascript]?view plaincopy
  • return?{??
  • ??????invoke:?invoke,??
  • ??????instantiate:?instantiate,??
  • ??????get:?getService,??
  • ??????annotate:?createInjector.$$annotate,??
  • ??????has:?function(name)?{??
  • ????????return?providerCache.hasOwnProperty(name?+?providerSuffix)?||?cache.hasOwnProperty(name);??
  • ??????}??
  • ????};??
  • ?

    其中前三個方法很重要,例如可以通過get方法獲得一個需要注入的組件:

    [javascript]?view plaincopy
  • var?comp?=?injector.get('component');??
  • 在Angular中,依賴注入可謂無孔不入。通常在兩種場景(函數(shù))下會使用到依賴注入:

  • 工廠方法定義的組件(components):如directive,factory,filter,provider,controller等。這些工廠函數(shù)需要注冊到某個模塊上。controller比較特殊,它雖然也是一種組件,但是特別之處是它與某個DOM元素關聯(lián),因此可以注入$scope?service,而其他組件只能注入$rootScope?service。
  • 模塊提供的run/config方法
  • 我們稱定義組件的工廠方法和run/config方法是可注入的。 Angular支持三種定義依賴注入的方式: 數(shù)組標注:最常用且推薦的方式。例如: [javascript]?view plaincopy
  • myApp.controller('smallCatCtrl',?['$scope',?function($scope){??
  • ????$scope.sayCat?=?function(){??
  • ????????alert('I?Love?Circle!');??
  • ????}??
  • }]);??
  • $inject屬性標注:這種方式通過工廠方法的$inject屬性聲明依賴的組件,主要用于js被壓縮/混淆時,變量被重命名的情況。例如: [javascript]?view plaincopy
  • var?MyController?=?function($scope,?myService)?{??
  • ??//?...??
  • }??
  • MyController.$inject?=?['$scope',?'myService'];??
  • myApp.controller('MyController',?MyController);??
  • 隱式標注:這種方法最簡易,Angular會通過工廠方法的參數(shù)名,推斷找到依賴的組件,但不能用于js被壓縮/混淆的情況,因為這種情況下方法的參數(shù)可能被重命名導致Angular無法定位依賴。例如: [javascript]?view plaincopy
  • myApp.controller('smallCatCtrl',?function($scope){??
  • ????$scope.sayCat?=?function(){??
  • ????????alert('I?Love?Circle!');??
  • ????}??
  • });??
  • 另外,Angular支持使用嚴格注入模式:ng-strict-di,該聲明與ngApp位于同一元素。嚴格模式下,不允許隱式注入,如果使用Angular會拋出異常。 要獲得Angular應用的injector,只需注入$injector 即可,有意思的是它知道如何注入自己。通過使用$injector service的invoke方法,可以將組件注入到任何方法中,如: [javascript]?view plaincopy
  • var?myFunction?=?function(hello)?{??
  • ??hello('My?Cat');??
  • };??
  • $injector.invoke(myFunction);??
  • 這段代碼將hello service注入到myFunction函數(shù)作為其一個參數(shù)。我們定義組件(如controller,directive,filter,factory)所使用的工廠方法就是通過invoke函數(shù)注入依賴的。例如在Angular啟動時,bootstrap方法會有如下邏輯: [javascript]?view plaincopy
  • injector.invoke(['$rootScope',?'$rootElement',?'$compile',?'$injector',??
  • ???????function?bootstrapApply(scope,?element,?compile,?injector)?{??
  • ????????scope.$apply(function()?{??
  • ??????????element.data('$injector',?injector);??
  • ??????????compile(element)(scope);??
  • ????????});??
  • ??????}]??
  • ????);??
  • $rootScope等service被注入到bootstrapApply方法中,輔助完成啟動過程。 injector針對每個可注入組件只創(chuàng)建一個實例(調(diào)用injector.instantiate方法),創(chuàng)建之后會將其緩存,以備后續(xù)訪問。如圖:(來源:https://docs.angularjs.org/guide/di) 三、Angular中的可注入組件 前面談到了工廠方法以及config/run方法為可注入方法。下面稍微展開一點。首先從Angular中的provider說起。provider的概念比較抽象,簡單來說,provider支持為某個組件(如factory,service,value等)在加載時提供一些配置。最終,每個provider會被注入到特定的組件使用。在Angular中,factory,service和value本質(zhì)上都是一種provider,Angular會執(zhí)行如下代碼定義這些provider: [javascript]?view plaincopy
  • myApp.config(function($provide)?{??
  • ??$provide.provider('sayHello',?function()?{??
  • ????this.$get?=?function()?{??
  • ??????return?function(name)?{??
  • ????????alert("Hello,?cat?"?+?name);??
  • ??????};??
  • ????};??
  • ??});??
  • });??
  • 這里的config方法稍后再談。$provide 是Angular內(nèi)部提供的一個service,用來定義provider。$get方法返回了真正的service。為了簡單,使用具體的provider類型進行定義也可以,這樣還可省去get方法: [javascript]?view plaincopy
  • myApp.config(function($provide)?{??
  • ??$provide.factory('sayCat',?function()?{??
  • ????return?function(name)?{??
  • ??????alert("Hello,?Cat"?+?name);??
  • ????};??
  • ??});??
  • });??
  • 這樣就定義了一個factory service。如果把這套定義邏輯抽象出來,就成了Angular模塊的一系列定義service的方法: [javascript]?view plaincopy
  • myMod.factory("sayHello",?...);??
  • myMod.service("sayHello",?...);??
  • myMod.value("Cat",?...);??
  • 這些方法在調(diào)用時實際執(zhí)行仍然是前面代碼段所示的完整版本(有get和provider方法)。

    下面說說config/run方法。Angular在加載模塊時經(jīng)過兩個階段:config和run。傳入config函數(shù)的方法會在當前模塊加載時執(zhí)行;傳入run函數(shù)的方法會在所有模塊加載結(jié)束后執(zhí)行。因此,在config階段即可配置多個provider,但是在config階段,只有provider可以注入,因此自定義的service無法注入到config中。這也好理解,因為config階段是對service進行配置的而不是使用service本身。在前面的代碼中,$provide service本身就是一個provider(對于Angular應用來講相當于一個'元provider'),在模塊加載時會調(diào)用$provide的provider方法定義一個新的provider。再看一個具體的例子:

    ?

    [javascript]?view plaincopy
  • define(['angular'],?function(angular){??
  • ????return?angular.module('myCat',?[])??
  • ????.provider('hello',?function()?{??
  • ????????var?firstName?=?'';??
  • ????????this.makeName?=?function(first){??
  • ????????????firstName?=?first;??
  • ????????}??
  • ????????this.$get?=?function()?{??
  • ????????????return?function(name)?{??
  • ????????????????alert("Hello,?"?+?firstName?+?'??'?+?name);??
  • ????????????};??
  • ??????};??
  • ????})??
  • ????.config(function(helloProvider){??
  • ????????helloProvider.makeName('Circle');??
  • ????})??
  • ????.controller('catCtrl',?[??
  • ????????'$scope',???
  • ????????'$q',???
  • ????????'hello',??
  • ????????function($scope,?$defer,?hello){??
  • ????????????$scope.catName?=?"";??
  • ????????????$scope.sayHello?=?function(){??
  • ????????????????hello('Jiang');//output?'Hello,?Circle?Jiang'??
  • ????????????};??
  • ????????}]??
  • ????);??
  • });??

  • 在myCat模塊中定義了一個名為hello的provider。該provider提供了一個makeName配置方法,用于設置firstName。$get方法返回一個函數(shù)用于打印一句話,這是該provider的核心功能(記住provider具體化后仍然是一個service,用于完成某種工作,只不過它是可配置的)。在config方法中,注入的函數(shù)參數(shù)對象名為系統(tǒng)生成的provider的名字helloProvider,自動添加了'provider'后綴。這里調(diào)用配置方法,這個配置會在未來使用該provider提供的功能時生效。最后,在controller定義中,注入了hello provider,并在sayHello方法中調(diào)用之,完成功能。這種模式應用十分廣泛,一個例子是開源項目ui-router中的$state service以及對應的$stateProvider(provider的$get方法返回了一個$state對象,定義了go等方法和屬性,使用過的開發(fā)者應該很熟悉了)。只有provider類型的service可以注入到其他組件中供其使用(如factory,constant等)。

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    值得注意的是,可以向controller注入service(可注入),但controller不能被注入其他組件中,因為controller本身不是provider。Angular維護著一個service名為$controller,定義并注冊一個controller的工作實際上由該service的provider完成,當需要創(chuàng)建controller實例時,$controller會調(diào)用$injector的invoke方法完成依賴注入,$controllerProvider的$get方法返回一個實例。 類似地,directive對應$compile service,filter對應$filter service,不再詳述。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/tongbiao/p/6830118.html

    總結(jié)

    以上是生活随笔為你收集整理的理解AngularJS中的依赖注入的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。