首先,爲了舉栗子,先寫好以下的模型,控制器,html:html
html:git
<!DOCTYPE html> <html ng-app="serviceApp"> <head> <title>服務</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script src="script.js"></script> <!-- <script src="script_2.js"></script>--> </head> <body > <div ng-controller="myCtrl"> name:{{name}} <br/> age:{{age}} <br/> love:{{love}} <br/> money:{{money}} <br/> id:{{id}} </div> <hr/> <div ng-controller="myOtherCtrl"> name:{{name}} <br/> love:{{love}} <br/> </div> <hr/> </body> </html>
js:github
var serviceApp = angular.module('serviceApp',[]); serviceApp.controller('myCtrl',function($scope,myConfig){ $scope.name = myConfig.name; $scope.love = myConfig.love; $scope.age = myConfig.age; $scope.money = myConfig.money; $scope.id = myConfig.getId(); $scope.$watch(myConfig.love,function(){$scope.love = myConfig.love;});
})
serviceApp.controller('myOtherCtrl',function($scope,myConfig){ $scope.name = myConfig.name; $scope.love = myConfig.love; angular.extend(myConfig,{love:'zxg'}); $scope.$watch(myConfig.love,function(){$scope.love = myConfig.love;}); });
如上,serviceApp模型裏有兩個控制器,myCtrl和myOtherCtrl,這兩個控制器都注入了myConfig這個服務.咱們在後面就經過建立不一樣的myConfig服務來查看結果json
一.constant服務:設計模式
app.constant('name',obj)閉包
name爲服務的名字,obj爲一個json對象.app
js:ide
serviceApp.constant('myConfig',{ name:'code_bunny', age:12, getId:function(){ return 1 } });
運行結果: http://jsfiddle.net/f9qq0t50/1/函數
說明:this
constant建立服務返回一個json對象(也就是第二個參數中傳入的對象),這個對象裏能夠有參數,能夠有方法,而且,屬性和方法均可以在控制器中修改,新增,可是按照它的設計本意,通常constant建立的服務不會去修改它的內容,須要修改內容,最好用value來建立服務.
注意點:
1.它是一個引用對象,不管被注入多少個控制器中,實際都指向同一個對象,因此,不管修改其中的哪個,其它全部的服務都會被改變.
2.服務修改事後,ng不會自動同步,簡單的說,就是它沒有作到自動雙向綁定數據,好比在這裏給服務新增了love屬性:angular.extend(myConfig,{love:'zxg'}),我須要使用$scope.$watch(myConfig.love,function(){$scope.love = myConfig.love;})這樣才能把love屬性值同步到視圖中.
3.constant服務不能經過decorator進行裝飾,(什麼是裝飾下面會講到)
二.value服務:
app.value('name',obj)
name爲服務的名字,obj爲一個json對象.
js:
serviceApp.value('myConfig',{ name:'code_bunny', age:12, getId:function(){ return 1 } });
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 }) });
運行結果:
說明:
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 } }
裝飾部分代碼同上.
運行結果:
說明:
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