AngularJS: Service vs provider vs factory
技术背景
在AngularJS开发中,Service、Factory和Provider是用于创建和管理可复用对象的重要概念,它们都基于依赖注入机制,帮助开发者在不同组件间共享代码和数据。理解它们的区别和使用场景,有助于写出更高效、可维护的代码。
实现步骤
Services
- 语法:
module.service('serviceName', function);
- 结果:当把
serviceName
作为可注入参数声明时,会得到传入service
函数的实例,即new FunctionYouPassedToService()
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var app = angular.module('myApp', []); app.service('servicePattern', function() { this.firstName = 'James'; this.lastName = 'Bond'; this.greet = function() { console.log('My Name is ' + this.firstName + this.lastName); }; });
app.controller('myServiceCtrl', function($scope, servicePattern) { servicePattern.greet(); });
|
Factories
- 语法:
module.factory('factoryName', function);
- 结果:当把
factoryName
作为可注入参数声明时,会得到调用传入module.factory
的函数引用所返回的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var app = angular.module('myApp', []); app.factory('factoryPattern', function() { var data = { 'firstName': 'Tom', 'lastName': 'Cruise', greet: function() { console.log('hello!' + this.firstName + this.lastName); } }; return data; });
app.controller('myFactoryCtrl', function($scope, factoryPattern) { factoryPattern.greet(); });
|
Providers
- 语法:
module.provider('providerName', function);
- 结果:当把
providerName
作为可注入参数声明时,会得到(new ProviderFunction()).$get()
。构造函数在调用$get
方法之前被实例化,ProviderFunction
是传入module.provider
的函数引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| var app = angular.module('myApp', []); app.provider('providerPattern', function providerConstructor() { this.firstName = 'Arnold '; this.lastName = ' Schwarzenegger'; this.greetMessage = ' Welcome, This is default Greeting Message'; this.setGreetMsg = function(msg) { if (msg) { this.greetMessage = msg; } }; this.$get = function() { var firstName = this.firstName; var lastName = this.lastName; var greetMessage = this.greetMessage; var data = { greet: function() { console.log('hello, ' + firstName + lastName + '! ' + greetMessage); } }; return data; }; });
app.config(function(providerPatternProvider) { providerPatternProvider.setGreetMsg(' How do you do ?'); });
app.controller('myProviderCtrl', function($scope, providerPattern) { providerPattern.greet(); });
|
最佳实践
- Factory:适用于创建可复用的工具函数、数据处理逻辑等,返回值可以是任意类型,包括对象、函数等。
- Service:适合创建自定义类型的对象,使用
this
关键字添加属性和方法,通常用于封装业务逻辑。 - Provider:当需要在应用启动前对服务进行全局配置时使用,例如设置API URL、默认参数等。
常见问题
this
关键字的使用问题:在Service
中使用this
时,要注意函数调用时的上下文,避免this
指向错误。可以使用bind
方法来绑定正确的上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| angular.service('ScoreKeeper', function($http) { this.score = 0; this.getScore = function() { return this.score; }; this.setScore = function(newScore) { this.score = newScore; }; this.addOne = function() { this.score++; }; });
$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper));
|
- 注入限制问题:
Value
可以注入到Service
和Factory
中,但不能注入到Provider
的创建函数中,不过可以注入到Provider
的$get
函数中。
1 2 3 4 5 6 7 8 9 10 11
| var myApp = angular.module('MyAppName', []); myApp.value('b', {name: 'Jones'});
myApp.provider('greetProvider', function() { this.$get = function(b) { this.lastName = b.name; return this; }; });
|