angular五種服務詳解
在這之前angular學習筆記(十五)-module裡的"服務"這篇文章裡,已經大致講解了ng中的"服務",在之後的很多地方也用到了服務,但是,所有的服務都是使用app.factory來建立的.但其實,建立服務有5種方法,這篇文章就來具體講解ng中的五種服務型別.
一.constant服務:
app.constant("name",obj)
name為服務的名字,obj為一個json物件.
js:
serviceApp.constant("myConfig",{ name:"code_bunny", age:12, getId:function(){ return1 } });
執行結果: http://jsfiddle.net/f9qq0t50/1/
說明:
constant建立服務返回一個json物件(也就是第二個引數中傳入的物件),這個物件裡可以有引數,可以有方法,並且,屬性和方法都可以在控制器中修改,新增,但是按照它的設計本意,一般constant建立的服務不會去修改它的內容,需要修改內容,最好用value來建立服務.
注意點:
1.它是一個引用物件,無論被注入多少個控制器中,實際都指向同一個物件,所以,無論修改其中的哪一個,其它所有的服務都會被改變.
2.服務修改過後,ng不會自動同步,簡單的說,就是它沒有做到自動雙向繫結資料,比如在這裡給服務新增了love屬性:angular.extend(myConfig,{love:"zxg"})
3.constant服務不能通過decorator進行裝飾,(什麼是裝飾下面會講到)
二.value服務:
app.value("name",obj)
name為服務的名字,obj為一個json物件.
js:
serviceApp.value("myConfig",{ name:"code_bunny", age:12, getId:function(){ return1 } });
serviceApp.config(function($provide){ $provide.decorator("myConfig",function($delegate){ $delegate.money = "100w"; return $delegate }) });
執行結果: http://jsfiddle.net/p0dqr7wy/1/
說明:
value建立服務返回一個json物件(也就是第二個引數中傳入的物件),這個物件裡可以有引數,可以有方法,並且,屬性和方法都可以在控制器中修改,新增,按照它的設計本意,如果屬性和方法需要被修改內容,就用value來建立服務.
constant和value主要就是用於存放一些資料或方法以供使用,區別是constant一般是存放固定內容,value存放可能會被修改的內容
注意點:
1.同constant注意點1
2.同constant注意點2
3.value可以被裝飾,所以這裡myConfig服務擁有了money屬性.(裝飾具體怎麼用,下面會說)
三.factory服務
app.factory("name",function(){return obj})
name為服務的名字,第二個引數傳入一個函式,函式需要有一個返回值obj,返回一個物件.實際被注入的服務就是這個物件.
js:
serviceApp.factory("myConfig",function(){ var myname = "code_bunny"; var age = 12; var id = 1; return { name: myname, age: age, getId: function(){ return id } } });
或者是這樣:
serviceApp.factory("myConfig",function(){ return new constructorFun() }); function constructorFun(){ var myname = "code_bunny"; var age = 12; var id = 1; this.name = myname; this.age = age; this.getId = function(){ return id } }
裝飾部分程式碼:
serviceApp.config(function($provide){ $provide.decorator("myConfig",function($delegate){ console.log($delegate); $delegate.money = "100w"; return $delegate }) });
執行結果:
http://jsfiddle.net/8kuxt3xc/
http://jsfiddle.net/ua2y617q/
說明:
factory服務是最常見最常用的服務型別,幾乎可以滿足90%的自己開發的需求,使用它可以編寫一些邏輯,通過這些邏輯最後返回所需要的物件.比如使用$http來獲取一些資料.我們就在factory建立的服務裡抓取資料,最後返回.
它和constant,value最大的區別是,factory服務是有一個處理過程,經過這個過程,才返回結果的.
注意點:
1.同constant注意點1
2.同constant注意點2
3.factory返回的服務也可以被裝飾,所以這裡myConfig服務擁有了money屬性.(裝飾具體怎麼用,下面會說)
四.service服務
app.service("name",constructor)
name為服務的名字,constructor是一個建構函式.
js:
serviceApp.service("myConfig",function(){ var myname = "code_bunny"; var age = 12; var id = 1; this.name = myname; this.age = age; this.getId = function(){ return id } });
或者是這樣:
serviceApp.service("myConfig",constructorFun); function constructorFun(){ var myname = "code_bunny"; var age = 12; var id = 1; this.name = myname; this.age = age; this.getId = function(){ return id } }
裝飾部分程式碼同上.
執行結果:
http://jsfiddle.net/1qj8m5ot/
http://jsfiddle.net/0bh67cog/
說明:
service和factory的區別在於,它第二個引數傳入的是一個建構函式,最後被注入的服務是這個建構函式例項化以後的結果.所以基本上使用service建立的服務的,也都可以使用factory來建立.
所以這裡,factory服務的第二種寫法和使用service是一致的:
serviceApp.factory("myConfig",function(){ return new constructorFun() }); //等價於 serviceApp.service("myConfig",constructorFun);
注意點:
1.同constant注意點1
2.同constant注意點2
3.service返回的服務也可以被裝飾,所以這裡myConfig服務擁有了money屬性.(裝飾具體怎麼用,下面會說)
五.provider服務
app.provider("name",function(){ .... return { ... $get:function(){ ... return obj } } })
name為服務的名字,第二個引數接受一個函式,函式返回一個物件,返回的物件比如要有$get方法,$get方法必須要返回一個物件obj,這個物件就是真正被注入的服務.
栗子一:
js:
serviceApp.provider("myConfig",function(){ return { $get:function(){ var myname = "code_bunny"; var age = 12; var id = 1; return { name: myname, age: age, getId: function(){ return id } } } } });
裝飾部分程式碼同上.
執行結果: http://jsfiddle.net/2pz2ft73/
說明:
provider服務的第二個引數的返回值中必須要有$get方法(除了$get,還可以有其它方法,後面的例子會說到),$get方法就相當於factory服務的第二個引數,最後要返回一個物件,這個物件就是真正被注入的服務:
栗子二:
js:
serviceApp.provider("myConfig",function(){ var id = 1; return { setID:function(newID){ id = newID }, $get:function(){ var myname = "code_bunny"; var age = 12; return { name: myname, age: age, getId: function(){ return id } } } } }); serviceApp.config(function(myConfigProvider){ myConfigProvider.setID(2) });
裝飾部分程式碼同上.
執行結果:http://jsfiddle.net/hcpemex3/
說明:
這裡的provider服務不僅僅返回了$get方法,還返回了setID方法,然後id變數是寫在函式裡的,返回值的外面,形成一個閉包,可以被修改.
然後,在provider服務裡定義的方法,可以在config函式裡呼叫.注意呼叫的格式:
serviceApp.config(function(myConfigProvider){ myConfigProvider.setID(2) });
被注入的服務名不叫myConfig,而是myConfigProvider.然後在函式裡面可以呼叫myConfigProvider的setID方法(也就是myConfig的setID方法).
通過這種方式,使得我們的服務可以被手動配置,比如這裡可以配置id.
ng有很多內建的服務都有這樣的功能,比如$route服務,$location服務,當我們通過$routeProvider和$locationProvider來配置的時候,其本質就是這些服務是通過provider建立的.
注意點:
1.同constant注意點1
2.同constant注意點2
3.provider返回的服務也可以被裝飾,所以這裡myConfig服務擁有了money屬性.(裝飾具體怎麼用,下面會說);
六.裝飾服務
其實通過上面這麼多的例子,看也能看懂裝飾是什麼了...
app.config(function($provide){ $provide.decorator("name",function($delegate){ $delegate.money = "100w"; return $delegate }) });
同樣是通過config,在引數函式中注入$provider服務,$provider服務有個decorator方法,它接受兩個引數,第一個引數"name",是要被裝飾的服務的名字,第二個引數是一個函式,函式中注入$delegate,$delegate就是被裝飾的服務的例項,然後在函式中操作$delegate,就相當於操作了該服務的例項.
注意:
1.最後一定要return $delegate,這樣服務才算被裝飾完成了.
2.constant服務是不能被裝飾的.
栗子就不說了吧,上面的都是~
總結上面的內容:
1.服務的例項被注入到控制器以後,都是一個引用物件,無論被注入多少個控制器中,實際都指向同一個物件,所以,無論修改其中的哪一個,其它所有的服務都會被改變.
2.服務的例項被修改過後,ng不會自動同步,需要使用$scope.$watch()監測其變化並手動重新整理檢視.
3.constant服務不能通過decorator進行裝飾.
4.一些固定的引數和方法,使用constant
5.可能被修改的引數和方法,使用value
6.通過邏輯處理後得到的引數或方法,使用factory
7.可以使用factory的也可以使用service,反之亦然(一般就是用factory)
8.可以手動配置引數的服務,使用provider
七.可以建立不同例項的服務
之前我們說到,所有的服務的例項都是引用物件,無論被注入多少個控制器中,實際都指向同一個物件,所以,無論修改其中的哪一個,其它所有的服務都會被改變.這就是ng服務的設計模式,一般不需要去改變,但如果有特殊需要,要能夠每次注入控制器後得到新的例項,可以這樣做:
我們給服務添加了一個方法,每次執行一次這個方法,都會建立一個新的例項,這樣,雖然在控制器裡注入的是服務例項還是同一個,但是在呼叫建立例項方法的時候,都會建立一個新的例項,然後就可以單獨修改這個例項,而不會影響到其它控制器:如下
js:
var serviceApp = angular.module("serviceApp",[]); serviceApp.controller("myCtrl",function($scope,myConfig){ var myConfigConstant = myConfig.create(); $scope.name = myConfigConstant.name; $scope.age = myConfigConstant.age; angular.extend(myConfigConstant,{love:"zxg"}); $scope.love = myConfigConstant.love; $scope.id = myConfigConstant.getId(); $scope.$watch(myConfigConstant.name,function(){$scope.name = myConfigConstant.name;}); myConfigConstant.name = "white_bunny"; }); serviceApp.controller("myOtherCtrl",function($scope,myConfig){ var myConfigConstant = myConfig.create(); $scope.love = myConfigConstant.love; $scope.name = myConfigConstant.name; $scope.$watch(myConfigConstant.name,function(){$scope.name = myConfigConstant.name;}); }); /************************建立例項的服務************************/ serviceApp.factory("myConfig",function(){ return { //服務返回的物件有一個create方法,該方法每次被執行都會返回一個新的constructorFun例項 create: constructorFun.createNew } }); //建立一個建構函式 function constructorFun(){ var myname = "code_bunny"; var age = 12; var id = 1; this.name = myname; this.age = age; this.id = id } //給建構函式新增createNew方法,用於例項化一個constructorFun. constructorFun.createNew = function(){ return new constructorFun() }; //給建構函式新增原型的方法.使得它的例項可以繼承. constructorFun.prototype = { getId: function(){ return this.id } };
執行效果: http://jsfiddle.net/fpoq4deo/1/
好了~五種服務型別就全部講完啦~~~
全部程式碼託管: https://github.com/OOP-Code-Bunny/angular/tree/master/service