angularjs - service 和factory的困惑

  显示原文与译文双语对照的内容

我理解,在工厂内部,我返回一个注入到控制器中的对象。 在一个服务中,我使用 this 处理对象,而不返回任何东西。

我假设服务总是单例,而且新工厂对象被注入在每个控制器。 然而,事实是,工厂对象也是单一的?

演示的示例代码:


var factories = angular.module('app.factories', []);
var app = angular.module('app', ['ngResource', 'app.factories']);

factories.factory('User', function () {
 return {
 first: 'John',
 last: 'Doe'
 };
});

app.controller('ACtrl', function($scope, User) {
 $scope.user = User;
});

app.controller('BCtrl', function($scope, User) {
 $scope.user = User;
});

ACtrl 中更改 user.first 时,会发现 BCtrl 中的user.first 也被改变,比如 User 是一个单独的?

我的假设是一个新的实例被注入到一个带有工厂的控制器中?

时间:

Live示例

"helloworld"示例

使用 factory/service/provider :


var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
 this.sayHello = function() {
 return"Hello, World!"
 };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
 return {
 sayHello: function() {
 return"Hello, World!"
 }
 };
});

//provider style, full blown, configurable version 
myApp.provider('helloWorld', function() {
//In the provider function, you cannot inject any
//service or factory. This can only be done at the
//"$get" method.

 this.name = 'Default';

 this.$get = function() {
 var name = this.name;
 return {
 sayHello: function() {
 return"Hello," + name +"!"
 }
 }
 };

 this.setName = function(name) {
 this.name = name;
 };
});

//hey, we can configure a provider! 
myApp.config(function(helloWorldProvider){
 helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

 $scope.hellos = [
 helloWorld.sayHello(),
 helloWorldFromFactory.sayHello(),
 helloWorldFromService.sayHello()];
}​

以下是主要差异:

服务

语法: module.service( 'serviceName', function );

结果:当宣布名作为可注射参数为你提供传递给 module.service 函数的实例。

用途︰可用于共享实用程序可通过简单地将( ) 追加到注入的函数引用来调用的函数的 也可以用 injectedArg.call( this ) 或者类似的方式运行。

工厂

语法: module.factory( 'factoryName', function );

结果:当宣布factoryName作为可注射参数将提供你值调用函数返回的引用传递给 module.factory

用途:可用于返回一个 '类' 函数,可以新创建实例的ed。

同时检查 AngularJS的文档和类似的问题关于 stackoverflow 困惑服务 vs 工厂。

下面是使用服务和工厂列表的示例。 阅读有关 AngularJS服务 vs 工厂的更多信息。

对于我来说,当我意识到它们都以同样的方式工作时,启示就会显现出来: 通过运行一些之后,他们存储值,然后咳嗽相同的存储价值当引用通过依赖注入。

假设我们有:


app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

两者之间的区别在于:

  1. a 存储的值来自运行 fn
  2. b 存储的值来自 newfn
  3. c 存储的值来自于首先通过 newfn 获取实例,然后运行实例的$get 方法

也就是说,Angular 中有一个类似缓存对象的东西,每个注入的值只在第一次被注入时被分配一次,并且在哪里:


cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

这就是为什么我们在服务中使用 this,并在提供者中定义一个 this.$get

希望这有帮助

添加到第一个答案,我认为. service() 是针对那些在更面向对象的风格( 使用 this/prototype/Constructor 函数) 中编写代码的人。

工厂是为编写代码更自然的开发人员编写代码的开发者,我更喜欢工厂风格,向前迈进。

查看 angular.js 中的。service和。factory方法的源代码- 内部都是调用提供程序方法:


 function provider(name, provider_) {
 if (isFunction(provider_)) {
 provider_ = providerInjector.instantiate(provider_);
 }
 if (!provider_.$get) {
 throw Error('Provider ' + name + ' must define $get factory method.');
 }
 return providerCache[name + providerSuffix] = provider_;
 }

 function factory(name, factoryFn) { 
 return provider(name, { $get: factoryFn }); 
 }

 function service(name, constructor) {
 return factory(name, ['$injector', function($injector) {
 return $injector.instantiate(constructor);
 }]);
 }

下面是一些服务 vs 工厂的例子,这些工厂可能有助于查看它们之间的差异。 基本上,一个服务已经调用了"新建。。",它已经被实例化。 工厂未自动实例化。

基本示例

返回具有单个方法的类对象

这是一个具有单一方法的服务:


angular.service('Hello', function () {
 this.sayHello = function () {/*.. . */};
});

这是一个工厂,它返回一个带有方法的对象:


angular.factory('ClassFactory', function () {
 return {
 sayHello: function () {/*.. . */}
 };
});

返回值

返回数字列表的工厂:


angular.factory('NumberListFactory', function () {
 return [1, 2, 3, 4, 5];
});

console.log(NumberListFactory);

返回数字列表的服务:


angular.service('NumberLister', function () {
 this.numbers = [1, 2, 3, 4, 5];
});

console.log(NumberLister.numbers);

两种情况下的输出相同,数字列表。

高级示例

"使用工厂的类"变量

在这个例子中,我们定义一个 CounterFactory,它递增或者递减一个计数器,你可以得到当前计数,或者获取已经创建的CounterFactory对象数:


angular.factory('CounterFactory', function () {
 var number_of_counter_factories = 0;//class variable

 return function () {
 var count = 0;//instance variable
 number_of_counter_factories += 1;//increment the class variable

//this method accesses the class variable
 this.getNumberOfCounterFactories = function () {
 return number_of_counter_factories;
 };

 this.inc = function () {
 count += 1;
 };
 this.dec = function () {
 count -= 1;
 };
 this.getCount = function () {
 return count;
 };
 }

})

我们使用 CounterFactory 创建多个计数器。 我们可以访问类变量来查看创建了多少计数器:


var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

这里代码的输出是:


people 0
people 1
counters 1
places 0
counters 2
counters 2

"工厂"以及"服务"是执行依赖注入的不同方式( 依赖注入) ) Angular 。 请阅读前面的问题以了解什么是问题。

所以当我们使用"服务"定义DI时,如下面的代码所示。 这将创建一个新的"记录器"对象全局实例并将它的注入到函数中。


app.service("Logger", Logger);//Injects a global object

使用"工厂"定义DI时,它不会创建一个实例。 它只是传递了方法,稍后消费者内部必须调用工厂来获取对象实例。


app.factory("Customerfactory", CreateCustomer);

下面是一个简单的图像,它展示了"服务"的DI进程是如何与"工厂"不同的。

enter image description here

当我们想根据场景创建不同类型的对象时,应该使用工厂。 例如根据场景中,我们想要创建一个简单的"客户"对象,或"客户""地址"对象或"客户""电话"对象。 是这里段落的详细说明

当我们有实用工具或者共享函数要注入像实用程序,记录器,错误处理程序等时,应该使用服务。

...