Angular中有幾種不同型別的services。每一種都有自己的獨特用法。
需要記住的非常重要的一點是service總是一個單體,無論是哪種型別的service。
註釋:單體是一種設計模式,它限制了每一個類僅能夠例項化為一個物件。無論我們在什麼地方注入我們的service,將永遠使用同一個例項。例子:
app.constant('fooConfig',{ config1: true, config2: "Default config2" });
Constant是一個非常有用的service,它經常被用來在指令中提供預設配置。因此如果你正在建立一個指令,並且你想要在給指令傳遞可選引數的同時進行一個預設配置,一個Constant就是一個好辦法。
作為一個constant,我們放入其中的值將不會改變。Contant service 基本上回事一個基本型別的值或者是一個物件。
例子:
app.value('fooConfig',{ config1: true, config2: "Default config2 but it can change" });
一個value service有點像是一個constant但是它是可以被改變的。它也經常被用在一個指令上面,來進行配置。一個value service有點像是一個factory service的縮小版,它經常用來儲存值但是我們不能在其中對值進行計算。
我們可以使用angular物件的extend方法來改變一個value service:
app = angular.module("app", []); app.controller('MainCtrl', function($scope, fooConfig) { $scope.fooConfig = fooConfig; angular.extend(fooConfig, {config3: "I have been extended"}); }); app.value('fooConfig', { config1: true, config2: "Default config2 but it can changes" });例子:
app.factory('foo', function() { var thisIsPrivate = "Private"; function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; });// or..
app.factory('bar', function(a) { return a * 2; });
Factory service是最普遍使用的service。它同樣也非常容易理解。
一個Factory是一個能夠返回任何資料型別的service。對於你如何建立它並沒有什麼可選項,你僅僅需要在其中返回一些東西即可。
正如前面所說的,所有的service型別都是單體,因此如果我們在一個地方修改了foo.variable,其他的地方也會相應的發生改變。
例子:
app.service('foo', function() { var thisIsPrivate = "Private"; this.variable = "This is public"; this.getPrivate = function() { return thisIsPrivate; }; });
Service service 和factory差不多。它們之間的區別在於service會接收一個構造器,因此當你第一次使用它的時候,它將會自動執行newFoo()來例項化一個物件。一定要記住如果你在其他的地方也使用了這個service,它將返回同一個物件。
事實上,上面的程式碼和下面的程式碼等價:
app.factory('foo2', function() { return new Foobar(); }); function Foobar() { var thisIsPrivate = "Private"; this.variable = "This is public"; this.getPrivate = function() { return thisIsPrivate; }; }
Foobar是一個類,我們在首次使用它的時候在我們的factory中將它例項化然後將它返回。和service一樣,Foobar將只會例項化一次然後下次當我們再次使用factory時它將返回同一個例項。
如果我們已經有了一個類,並且我們想將它用在service中,我們只需要編寫如下的程式碼:
app.service('foo3',Foobar);
Provider是factory的加強版。事實上,上一個例子中的factory程式碼等價於下面的provider程式碼:
app.provider('foo', function() { return { $get: function() { var thisIsPrivate = "Private"; function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; } }; });
一個provider中應當由一個$get函式,其中的內容就是我們想要注入我們應用中的部分,因此當我們將foo注入一個控制器時,我們實際上注入的是$get函式。
既然factory如此簡單,那我們為什麼還要使用provider呢?因為我們可以在config階段配置一個provider。因此我們可以編寫下面的程式碼:
app.provider('foo', function() { var thisIsPrivate = "Private"; return { setPrivate: function(newVal) { thisIsPrivate = newVal; }, $get: function() { function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; } }; }); app.config(function(fooProvider) { fooProvider.setPrivate('New value from config'); });
在這裡我們將thisIsPrivate移到了我們的$get函式的外面,然後我們建立了一個setPrivate來在一個config函式中修改thisIsPrivate。為什麼我們需要這樣做?這難道不比在factory中新增setter要容易嗎?除此之外,還有另外一個原因。
我們想要注入一個特定的物件但是我們想要提供一種方式來根據我們的需求進行一些配置。例如:一個service包含了一個使用jsonp的資源,我們想要配置具體使用的URL,或者我們想要使用一個第三方的service比如restangular來允許我們根據我們的需求來進行配置。
要注意到我們在config函式中放入的是nameProvider而不是name。在這裡,我們實際上還是對name進行配置。
看到這裡我們其實已經意識到了我們已經在應用中進行過一些配置了,像是$routeProvider以及$locationProvider,兩者分別用來配置我們的路由了html5模式。
那麼現在已經決定要使用前面的 foo service,但是其中還是缺少一個你想要的greet函式。你可以修改factory嗎?答案是不行!但是你可以裝飾它:
app.config(function($provide){ $provide.decorator('foo',function($delegate){ $delegate.greet = function(){ return "Hello, I am a new function of 'foo'"; } }); });
$provide是Angular用來在內部建立我們的service的東西。如果我們想要使用它的話可以手動來使用它或者僅僅使用在我們的模組中提供的函式(我們需要使用$provide來進行裝飾)。$provide有一個函式,decorator,它讓我們可以裝飾我們的service。它接收我們想要裝飾的service的名字並且在回撥函式中接收一個$delegate來代表我們實際上的service例項。
在這裡我們可以做一切我們想要的事情來裝飾我們的service。在上面的例子中,我們為我們原來的service新增了一個greet函式。接著我們返回了修改後的service。
經過修改以後,現在我們的factory中已經有了一個叫做greet的函式。
裝飾一個service的能力是非常實用的,尤其是當我們想要使用第三方的service時,此時我們不需要將程式碼複製到我們的專案中,而只需要進行一些修改即可。
注意:constant service不能被裝飾。
我們的services都是單體但是我們可以建立一個單體factory來建立新的例項。在你深入之前,記住Angular中的服務都是單體並且我們不想改變這一點。但是,在極少數的情況下你需要生成一個新的例項,你可以像下面這樣做:
function Person(json){ angular.extend(this,json); } Person.prototype = { update: function(){ this.name = "Dave"; this.country = "Canada"; } }; Person.getById = function(id){ return new Person({ name: "Jesus", country: "Spain" }); }; app.factory('personService',function(){ return { getById: Person.getById }; });
在這裡我們建立了一個Person物件,它接收一些json資料來初始化物件。然後我們在我們的原型(原型中的函式可以被Person的例項所用)中建立了一個函式,並且在Person上直接建立了一個函式(就像是類函式一樣)。
因此現在我們擁有了一個類函式,它將基於我們提供的id來建立一個新的Person物件,並且每一個物件都可以自我更新。現在我們僅僅需要建立一個能夠使用它的service。
當每次我們呼叫personService.getById時,我們都在建立一個新的Person物件,因此你可以在不同的控制器中使用這個service,即便當factory是一個單體,它也能生成新的物件。
Service是Angular中最酷的特性之一。我們可以使用很多方法來創造它們,我們僅僅需要找到符合我們需求的方法然後實現它。
英文原文:http://angular-tips.com/blog/2013/08/understanding-service-types/
來自:新知社群
相關閱讀
評論(2)