扯淡的話----------做爲一個老魔獸玩家,我很喜歡將寫代碼和玩遊戲進行對比,在使用不一樣的框架時,就好像咱們在切換天賦技能,拿盜賊來講,敏銳天賦有個技能叫暗影之舞(很久沒玩,不知道還在不),開了以後容許在非潛行狀態下使用潛行技能,好比偷襲,鎖喉什麼的,這就好像在框架裏咱們須要知道哪一個方法能夠在什麼狀態下使用,在什麼時間用,好比盜賊內戰時,高手會用消失來躲致盲,在須要爆發時,賊們也會消失進入潛行來一波爆發。。。。。因此知道咱們能夠作什麼,怎麼樣作,什麼時間作,是成爲高手必須的修行,好了,廢話很少說,進入正題。
Angular應用是由許多對象組成,這些對象根據必定的關係被關聯在一塊兒,大多數狀況下咱們並不須要關心它們是如何被組織在一塊兒,以及相互之間是如何進行協做的,但想要更親近angular,就必須瞭解這一過程。
大致上來講angular的對象能夠被分爲兩類,一類是像services這種由開發者定義的,用來提供應用所須要的公共API,一類是由angular框架定義好的具備特定用途的對象,好比controller、filter、directive等。那麼這些對象是如何被定義出來的?除了injector外別無它法,可是對於injector來講,它須要知道如何去定義這些對象,對於內置的那些對象來講,咱們固然不須要插手,angular爲此暴露了5個API,分別是value(),service(),factory(),constant(),以及最爲強大的provider(),前四個其實就是provider()的語法糖。雖然對象的建立是由injector來完成,但這5個方法倒是angular模塊的方法,也就是說咱們在調用的時候須要在模塊上去調用,例1:框架
var myModule = angular(「myModule」,[]); myModule.value(「name」,」superMan」);
在angular中,全部的服務都是單例對象,也就是說它們只會被調用一次,以後在injector中會保存服務的引用,在須要的時候將其看成依賴注入進去。
1、value()
例1中咱們已經定義了一個服務,那麼咱們就能夠在任何須要的時候把它注入到咱們的控制器中,例2:ide
myModule.controller(「myController」,[「name」,function(name){ this.name = name; }]); <body ng-controller = 「myController as con」> Name:{{con.name}} </body>
這樣咱們就能夠成功的拿到這個註冊的名字」superMan」,而且能夠在視圖中正確的讀到它。
它就是如此的簡單。
2、constant()
這個方法和value()同樣的簡單,惟一的不一樣是,constant()註冊的值能夠在angular運行的配置階段訪問到。例3:函數
myModule.constant(「prefix」,」ECS」); myModule.config([「prefix」,function(pre){ //這裏的pre將會被正確的訪問 }]); myModule.config([「name」,function(name){ //這裏去訪問name將會拋出錯誤,由於此時服務都尚未被註冊 }]);
angular應用的生命週期被分爲配置和運行兩大階段,在配置階段,咱們所寫的服務都尚未註冊進來,因此在這個時候去訪問經過value()方法註冊的值,是不可訪問到的。固然constant()註冊的值在運行階段也是能夠被正確的訪問的。也就是說它們一個是全週期可見,一個是隻有運行階段可見。
3、factory()
以上兩個方法都很是的簡單,註冊的值也同樣的簡單,實際狀況中咱們須要一些更爲複雜的服務來提供更加健全的功能。Factory()同它們相比具備更強的能力,一、經過依賴注入能夠引用到其它的服務。二、初始化服務。三、延遲加載服務,也就是說在須要的時候angular纔去初始化。例4:this
myModule.factory("name",function nameFactory(){ return "superMan"; });
咱們將例1中經過value()註冊的值用factory()重寫,這裏咱們用到了函數,這個函數能夠接受一個或多個參數,只要這些參數已經被angular註冊,它們就能被看成依賴被正確的加載進來,函數的返回值將被做爲服務的實例被其引用到。這就給咱們提供了更多的可能,咱們能夠返回一個簡單值 ,固然也能夠返回個對象或函數,總之看你須要。例5:調試
myModule.factory("fullName",["name",function fullNameFactory(name){ var firstName = "XX"; var fn = function(f,l){ return f + l; } return { name:fn(firstName,name) } }]);
在這裏,函數的名字不是必須的,可是最好給它起一個可以很容易辨識的名字,這在調試程序時將會很是有用,一旦出錯,你能夠很輕易的在堆棧追蹤中發現它。
4、service()
在面向對象的開發中,咱們常常會用到自定義的類,固然,咱們可使用factory()方法來把這些類註冊爲服務,例6:rest
function Person(name){ this.name = name; this.speak = function(){ console.log("my name is " + this.name); } } myModule.factory("person",["name",function person(name){ return new Person(name); }]);
在建立服務時,service()方法和factory()方法惟一的不一樣之處就是它使用new運算符來給咱們實例化一個對象,也就是這個時候咱們應該給service()傳入一個構造函數,構造函數能夠接受0個或多個參數,這些參數從哪來?固然是依賴注入,既然在factory()中咱們均可以依賴注入,在service()中固然也能夠,用service()來重寫例6:code
myModule.service("person",[「name」,Person]);
一目瞭然,無需多言。
5、provider()
前面說過,以上4種方法都是provider()的語法糖,也就是說上面4種方法具備的能力,provider()都具備。Providr()的能力是最強大的,但在實際開發中有時候會顯的矯枉過正,永遠記住,只選最適合你的。
對於provider()而言,它必須有一個$get()方法,這是區別於上面4種方法最爲明顯的地方,對於$get()的參數,可能經過依賴注入來獲取,這個函數就像factory()的工廠函數,實際上對於factory()而言,angular會自動給它的函數設置一個空的$get()方法。
另外,前面咱們提到過angular應用生命週期的2個階段,如同constant()方法,provider()方法固然也能夠在配置階段運行,所以,對於provider()它最適用的場景就是在應該啓動前給咱們暴露一些API,以便咱們能夠經過這些API對應用進行配置。它註冊的服務應該是咱們但願在不一樣的應用間能夠重用,且服務的行爲在各有應用間很是一致,或者說變化很是小。
例7:對象
myModule.provider("speakName",function speakNameProvider(){ var firstName = ""; this.addFirstName = function(f){ console.log(「my firstName is:」 + f); firstName = f; } this.$get= ["name",function speakNameFactory(name){ var fullName = firstName + name; return new Person(fullName); }]; });
假如咱們但願在應用配置階段加上一個姓,那麼就能夠經過暴露的API實現生命週期
myModule.config(["speakNameProvider",function(speakNameProvider){ speakNameProvider.addFirstName("XXX"); }]);
回到開頭說的,angular的對象分爲兩類,對於咱們能夠定義的,前面已經介紹完了,對於angular已經內置的一些對象,咱們在使用時候必須遵循它的規則,好比controller、directive、filter等。固然咱們定義好的這些服務能夠被做爲依賴注入到這些特殊對象中,好比:遊戲
myModule.directive("myName",["name",function myName(name){ return { restrict:"EA", scope:{}, link:function(scope,ele,attrs){ ele.text("name:" + name); } } }]);