1. 简介
AngularJS采用MVC架构,提供了服务的注册和以依赖注入方式使用服务的机制。服务是功能(方法)和数据(常量)的抽象,比如系统中关于用户信息相关的功能(头像、昵称、签名、生日、性别等信息的获取与修改)抽象后集中在一个对象中,那么这个对象就可以视为一个服务。服务可以通过angular.Module(常以var app = angular.module(‘my-app‘,[])方式获取)和$provider(以依赖注入方式获取)对象注册,常以依赖注入的方式使用使用。
每个服务有一个(字符串类型的)名字,在注册时提供,依赖注入子系统通过服务名获得服务对象。服务是单例的,因此每次获取到的服务都是同一个服务对象。
下面通过一个简单的示例来说明如何在代码中注册和使用服务,以及可能遇到的一个坑(依赖注入器$injector找不到服务Error: [$injector:unpr] Unknown provider: XXXXXX。通过查看源码发现angular注册服务时会在服务名后自动添加后缀"Provider",我之前有遇到依赖注入器死活找不到对应服务名,在我往依赖注入变量名后手动添加Provider后运行成功,但此问题没能重现,因此不能详解)。这个示例很简单,只是显示通过服务注册的5种方式(provider、factory、service、constant、value)注册服务(和数据),然后通过依赖注入的方式获取服务和数据,之后在网页上显示出。
5种方式中,后4种都是依赖于provider方式实现的,5种方式依次更特殊,更不灵活,注册也因此变得更简单。
2. provider方式
用provider注册服务常见的调用形式是:
var app = angular.module(‘app‘, []); app.provider(‘StarProvider‘, function () { console.log(‘provider constructor‘) //必须定义$get函数 this.$get = function () { console.log(‘provider $get func‘) var counter = 0; var obj = function () { }; obj.favorite = function () { return ‘李嘉欣x‘ + counter++; }; return obj; } });
provider函数中的重点是第二个参数,这个参数中必须定义$get函数,这将成为取得服务对象的getter函数。
3. factory方式
factory方式注册时,形式上类似provider,不同的是,第二个参数是一个工厂函数,该函数是一个有返回值的函数,返回值就是服务对象,angular在实现factory方式时,就是将factory第二个参数作为一个新对象的$get属性传递给provider,作为其第二个参数。
代码形式通常为:
app.factory(‘StarFactory‘, function () { console.log(‘factory constructor‘) var c = 0; var fac = {}; // 常先定义一个服务对象,然后定义其服务接口 fac.favorite = function () { return ‘关之琳x‘ + c++; }; return fac; });
4. service方式
factory到service的特殊化程序类似provider到factory,service的第二个参数不使用factory中的工厂模式,第二个参数就是服务对象的构造器,其中定义的公有属性就是服务的服务接口。可见,不像factory方式,service方式不再在第二个参数(可执行对象)中定义服务对象(上例中的fac变量),因其就是服务对象本身。以该方式注册服务的代码常以以下形式出现:
app.service(‘StarService‘, function () { console.log(‘service constructor‘) var c = 0; this.favorite = function () { //常以this.xxx方式定义服务接口 return ‘蓝洁瑛x‘ + c++; } })
5. constant、value方式
这两种方式用以注册常量(不变的量,并非就一定是字符串或数值类型),二者区别小,且不常被我使用,不详解,注册代码形式为:
app.constant(‘StarConstant‘, ‘邱淑贞-const‘); app.value(‘StarValue‘, ‘梅艳芳-val‘);
6. 服务使用方式(依赖注入)
三种依赖注入使用方式:匿名、内联、显示声明,这三种方式都要求首先声明angular内置服务(名字一般以$打头)。所有自定义provider的各种非常量形式服务(provider、factory、service)在被注册时会被自动添加"Provider"后缀(三种都是,并非provider添加Provider、factory添加Factory、service添加Service)。 1.推断式依赖注入:参数名必须与服务名一致,angular由此推断需要注入的服务 app.provider(‘this-service-name‘, function ($http, $scope, MyOtherService) {}) 2.内联:形式:[‘$builtIn1‘, ‘$builtIn2‘, ‘MyOtherService1‘, function(builtIn1Alias, builtIn2Alias,MyOtherService1Alias){}] app.provider(‘this-service-name‘, [‘$builtIn1‘, ‘$builtIn2‘, ‘MyOtherService1‘, function(builtIn1Alias, builtIn2Alias,MyOtherService1Alias){}]) 3.显示声明。将依赖声明到对象的$inject数组。var foo=function(){}; foo.$inject = [‘$builtIn1‘, ‘$builtIn2‘, ‘MyOtherService1‘] app.factory(‘StarFactory‘, foo)
7. 示例效果及代码
效果如下:
代码压缩包在网盘此处。