Angular.js Services
Angular带来了很多类型的services。每个都会它自己不同的使用场景。我们将在本节来阐述。
首先我们必须记在心里的是所有的services都是singleton(单例)的,这也是我们所希望得到的预期结果。
下面让我开始今天的services之旅吧:
Constant
示例:
app.constant('fooConfig', {
config1: true,
config2: "Default config2"
});
constant是个很有用的东东,我们经常会用于对directive之类的做配置信息。所以当你想创建一个directive,并且你希望能够做一些配置信息,同时给些默认的配置,constant是个不错的的选择。
constant可以译作常量,因为我们所设置的值value是不能被改变的。其可以接受基础类型和object对象。
Value
示例:
app.value('fooConfig', {
config1: true,
config2: "Default config2 but it can changes"
});
Value和上面的constant很相似,唯一是其在赋值后还可以被改变。它也被常用于directive配置信息。Value service只会保留values,我们不会在service中计算其值。
Factory
示例:
app.factory('foo', function() {
var thisIsPrivate = "Private";
function getPrivate() {
return thisIsPrivate;
}
return {
variable: "This is public",
getPrivate: getPrivate
};
});
Factory是我们最常用的service。其很容易被理解。
factory会返回一个object对象,至于你如何创建这个对象angular没任何限制。在示例中我选择了我喜欢的模式 Revealing module pattern,你可以选择其他你所希望的方式。
如我之前所说,所有的services都是singleton的,所以当我们修改foo.variable的时候,会影响到其他使用的地方。
Service
示例:
app.service('foo', function() {
var thisIsPrivate = "Private";
this.variable = "This is public";
this.getPrivate = function() {
return thisIsPrivate;
};
});
Service service和factory工作原理一样,只是他service接收的是一个构造函数,当第一次使用service的时候,angular会new Foo() 来初始化这个对象。以后的时候返回的都是同一个对象。
实际上,下面是factory等价的写法:
app.factory('foo2', function() {
return new Foobar();
});
function Foobar() {
var thisIsPrivate = "Private";
this.variable = "This is public";
this.getPrivate = function() {
return thisIsPrivate;
};
}
Foobar是一个class(类)在factory中我们手动初始化它,在返回它。和service一样Foobar class只在第一次初始化,并以后返回的都是同一个对象。
如果我们已经存在了一个class,那么我可以直接使用:
app.service('foo3', Foobar);
Provider
Provider 在angular中是个最终的高级选项,在上例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到controller,我们注入的是$get 函数。
为什么我们还需要provider,factory实现不是更简单吗?这是因为我们能够在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不就好了吗?这是一个不同的意图。
我们希望注入的是一个object对象,但是我们也希望能够提供一种方式去配置它。例如:一个包装了jsonp的资源resource的service,我们希望能够配置是从那个url获取资源,我们也将有个三方的消费者比如restangular允许我们去配置达到我们的目的。
注意在config函数我们需要用nameProvider替代name,然而消费者只需要用name。
可以看见在在我们的应用程序中已经配置了一些services,比如$routeProvider,$locationProvider,配置我们的routes和html5model 调整适应。
额外的福利:
福利1:装潢器Decorator
如果你觉得我给你的foo service缺少了你所需要的greet方法,你需要改变API吗?不,你可以用更好的方法装潢:
app.config(function($provide) {
$provide.decorator('foo', function($delegate) {
$delegate.greet = function() {
return "Hello, I am a new function of 'foo'";
};
return $delegate;
});
});
上例中$provide是angular内部用于创建我们所有service的service。如果我们希望在我们的应用程序中使用,我们可以手动的使用它(我们可以用$provide去装潢)。$provide有一个decorator的装潢函数,允许我们装潢我们的services,它接受我们所需要装潢的service的name和一个接受$delegate的回调函数,$delegate代表我们的原来的service实例。
在这里我们可以装潢我们的service。在本例中我们在原来的service实例上增加了一个greet函数,在返回修改过后的service。当我们消费这个service的时候,它将会包含一个greet的函数,你可以在下面的try it中看见。
对于使用来自第三方的service,当我们期望对其接口做一些扩展的时候,我们不需要copy它的代码到我们的项目来修改它,我们可以手动方便的使用装潢器去实现我们所想要的。
注意:上文中说的常量constant是不可以被装潢的。
福利2:创建非单例对象
如我们所知所有的service都是单例的,但是我们仍然可以创建一个非单例的对象。在我们深入之前,我们必须认识到大多数场景我们都会期望是个单例的service,我们也不会去改变这种机制。换句话在很少的场景中我们需要每次生成一个新的object对象。如下:
// Our class
function Person( json ) {
angular.extend(this, json);
}
Person.prototype = {
update: function() {
// Update it (With real code :P)
this.name = "Dave";
this.country = "Canada";
}
};
Person.getById = function( id ) {
// Do something to fetch a Person by the id
return new Person({
name: "Jesus",
country: "Spain"
});
};
// Our factory
app.factory('personService', function() {
return {
getById: Person.getById
};
});
在这里我们创建了一个Person对象,它几首一些json对象来初始化对象。接下来我们在prototype中创建了一个函数(可以从面向对象语言理解为实例方法),在我们直接在Person类上加了一个方法(可以理解为类方法,静态方法)。
所以我们有一个类方法将根据我们提供的id创建一个新的person对象,并每隔实例可以更新自己。接下来我们只需要创建一个service去消费它。
在任何时候我们调用personService.getByID,我们都会创建一个新的person对象,所以在不同的controller中你可以使用一份新的person对象,即使factory是单例的,但是它生产返回的却是新的object。
福利3:CoffeeScript
CoffeeScrip能够方便优雅的处理service,提供的优雅的方式去创建class。下面是福利2的示例用CoffeeScript改变后的:
app.controller 'MainCtrl', ($scope, personService) ->
$scope.aPerson = personService.getById(1)
app.controller 'SecondCtrl', ($scope, personService) ->
$scope.aPerson = personService.getById(2)
$scope.updateIt = () ->
$scope.aPerson.update()
class Person
constructor: (json) ->
angular.extend @, json
update: () ->
@name = "Dave"
@country = "Canada"
@getById: (id) ->
new Person
name: "Jesus"
country: "Spain"
app.factory 'personService', () ->
{
getById: Person.getById
}
译者注:本人一直在思考一篇《为什么需要在你的项目中尝试CoffeeScript》.CoffeeScript不仅仅优美语法,如果只是这样的话,充其量这也只是一些可有可无的语法糖而已,我们认为更重要的是它为我们写javascript带来了一些好的实践,规避了javascript的“坑”.但是也不得不考虑项目成员学习成本,如果你项目成员很多具有函数式编程的经历,javascript能力也不错,你完全可以去尝试。注:写CoffeeScript并不是说你不再需要javascript学习。
总结:
service是angularjs另一个非常酷的features。我们有许多方式去创建service,我们需要根据我们的应用场景选择正确的方式去实现它。译者注:这就好比我们常挂在嘴边的设计模式,重要的是正确的场景使用正确的模式。
本来原文来自:http://angular-tips.com/blog/2013/08/understanding-service-types/
Angular.js Services的更多相关文章
- (翻译)Angular.js为什么如此火呢?
在本文中让我们来逐步发掘angular为什么如此火: Angular.js 是一个MV*(Model-View-Whatever,不管是MVC或者MVVM,统归MDV(model Drive View ...
- Angular js 之动态传数据到下一个页面和动态通过ng-click进入不同的页面
+关于Angular js中一些千篇一律的后台获取数据 首先在services.js里面把服务写好 然后在controller里面把数据给打印出来 (首先需要把数据注入) +关于Angular js中 ...
- Angular.JS + Require.JS + angular-async-loader 来实现异步加载 angular 模块
传统的 angular 应用不支持异步加载模块,必须在 module 启动的时候,所有模块必须预加载进来. 通过使用 angular-async-loader 库,我们可以使用 requirejs 等 ...
- Angular JS 学习笔记(自定义服务:factory,Promise 模式异步请求查询:$http,过滤器用法filter,指令:directive)
刚学没多久,作了一个小项目APP,微信企业号开发与微信服务号的开发,使用的是AngularJS开发,目前项目1.0版本已经完结,但是项目纯粹为了赶工,并没有发挥AngularJS的最大作用,这几天项目 ...
- Angular.js为什么如此火呢?
在本文中让我们来逐步发掘angular为什么如此火: Angular.js 是一个MV*(Model-View-Whatever,不管是MVC或者MVVM,统归MDV(model Drive View ...
- soket.io.js + angular.js + express.js(node.js)
soket.io.js + angular.js + express.js(node.js) 今天搭建个soket.io.js + angular.js + express.js的环境, 采坑无数,特 ...
- Angular.js!(附:聊聊非原生框架项目)
最近,为了项目接触了一个很火的前端框架Angular.js,下面就Angular做一个简介吧(大牛请绕步,只针对没有接触过angular的人). Angular.js是一款精简的前端框架,如果要追溯它 ...
- angular.js的依赖注入解析
本教程使用AngularJS版本:1.5.3 angularjs GitHub: https://github.com/angular/angular.js/ Angula ...
- Web API 2 入门——使用ASP.NET Web API和Angular.js构建单页应用程序(SPA)(谷歌翻译)
在这篇文章中 概观 演习 概要 由网络营 下载网络营训练包 在传统的Web应用程序中,客户机(浏览器)通过请求页面启动与服务器的通信.然后,服务器处理请求,并将页面的HTML发送给客户端.在与页面的后 ...
随机推荐
- src/main/Java路径下的properties文件丢失
在pom中加入代码: <build> <resources> <resource> <directory>src/main/java</direc ...
- 关于node.js
JS是一种脚本语言,它的本身并不能进行编译和执行,在最早的时期只是作为浏览器的脚本,只能够在浏览器中执行操作,也就是说JS必须依赖一个运行环境作为载体才能够执行. 而nodejs是基于chromeV8 ...
- RecyclerView的介绍与使用
一.什么是RecyclerView 新的视图控件,是Android-support-v7-21版本中新增的一个Widgets,官方对于它的介绍则是:RecyclerView是ListView的升级版本 ...
- 运用TensorFlow处理简单的NLP问题
当前无论是学术界还是工业界,深度学习都受到极大的追捧,尤其是在Google开源深度学习平台TensorFlow之后,更是给深度学习火上浇油.目前在开源社区Github上所有开源项目中,TensorFl ...
- NFSv4的引用,迁移和备份(用户手册 v0.2)
RFC3530 定义了NFS文件系统迁移和引用的管理机制.文件系统定位功能通过fs_location属性向客户端提供文件系统的位置信息.fs_location属 性是一个包含有位置信息的列表,位置信息 ...
- iOS8中定位服务的变化(CLLocationManager协议方法不响应,无法回掉GPS方法,不出现获取权限提示)
最近在写一个LBS的项目的时候,因为考虑到适配iOS8,就将项目迁移到Xcode6.0.1上,出现了不能正常获取定位服务权限的问题. self.manger = [[CLLocationManager ...
- getComputedStyle的应用
后面有例子,所以把HTML,CSS样式写在前面 HTML结构: <div id="myDiv" style="background-color: lightseag ...
- Java 用程序给出随便大小的10 个数,序号为1-10,按从小到大顺序输出,并输出相应的序号?
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.uti ...
- SQL Server2008清除数据库日志
m缪国瑞 11:10:17 --'这里的DNName_Log 如果不知道在sys.database_files里是什么名字的话,可以用以下注释的语句进行查询USE dochuanGOSELECT f ...
- 【图文教程】Eclipse for PHP+XAMPP调试配置
一.下载安装XAMPP 下载地址:https://www.apachefriends.org/download.html, 一路“Next”,安装完毕. 二.下载Eclipse for PHP 下载地 ...