根据我的理解,当我在工厂中返回一个被注入到控制器的对象。当在服务中,我使用这个处理对象,不返回任何东西。

我假设服务总是单例的,并且每个控制器中都会注入一个新的工厂对象。然而,正如事实证明的那样,工厂对象也是单例的吗?

演示的示例代码:

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中,结果是那个用户。BCtrl中的first也改变了,例如User is a singleton?

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


当前回答

多亏了Pascal Precht的一篇博客文章,这帮助我理解了其中的区别。

服务是模块上的一个方法,它接受定义服务的名称和函数。你可以在其他组件中注入和使用特定的服务,比如控制器、指令和过滤器。工厂是模块上的一个方法,它还接受一个定义工厂的名称和函数。我们还可以像对服务那样注入和使用it。

用new创建的对象使用其构造函数的prototype属性的值作为原型,所以我找到了调用Object.create()的Angular代码,我相信它是服务构造函数的实例化。然而,工厂函数实际上只是一个被调用的函数,这就是为什么我们必须为工厂返回一个对象字面量。

下面是我为factory找到的angular 1.5代码:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) {
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    }

factory()函数的Angular源代码片段:

 function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
  }

它接受传递的名称和工厂函数,并返回一个具有相同名称的提供者,它有一个$get方法,也就是我们的工厂函数。无论何时你向注入器请求特定的依赖项,它基本上都是通过调用$get()方法向相应的提供者请求该服务的实例。这就是为什么在创建提供程序时需要$get()。

下面是angular 1.5中服务的代码。

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

事实证明,当我们调用service()时,它实际上调用了factory()!然而,它并不只是将我们的服务构造函数原样传递给工厂。它还传递一个函数,要求注入器通过给定的构造函数实例化一个对象。

换句话说,如果我们在某处注入MyService,代码中发生的事情是:

MyServiceProvider.$get(); // return the instance of the service

为了再次声明它,服务调用工厂,这是对应提供者上的$get()方法。此外,$injector.instantiate()是最终使用构造函数调用Object.create()的方法。这就是为什么我们在服务中使用“this”。

对于ES5,我们使用哪个并不重要:service()或factory(),它总是一个被调用的工厂,它为我们的服务创建了一个提供者。

您也可以对服务做同样的事情。然而,服务是一个构造函数,它不阻止我们返回对象字面量。所以我们可以使用我们的服务代码并以一种基本上与工厂完全相同的方式来编写它,换句话说,你可以将服务编写为工厂来返回一个对象。

为什么大多数人建议使用工厂而不是服务?这是我所见过的最好的答案,来自Pawel Kozlowski的书:Mastering Web Application Development with AngularJS。

工厂方法是获取对象的最常用方法 AngularJS依赖注入系统。它是非常灵活的,可以 包含复杂的创建逻辑。因为工厂是正规的 函数,也可以利用新的词法作用域来实现 模拟“私有”变量。这很有用,因为我们可以隐藏 给定服务的实现细节。”

其他回答

“工厂”和“服务”是angular中进行DI(依赖注入)的不同方式。

因此,当我们使用“service”定义DI时,如下面的代码所示。这将创建一个新的“Logger”对象的GLOBAL实例,并将其注入到函数中。

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

当您使用“工厂”定义DI时,它不会创建实例。它只是传递方法,之后消费者必须在内部调用工厂以获取对象实例。

app.factory("Customerfactory", CreateCustomer);

下面是一个简单的图像,直观地显示了“服务”的DI流程与“工厂”的不同之处。

当我们想要根据场景创建不同类型的对象时,应该使用Factory。例如,根据不同的场景,我们想要创建一个简单的“Customer”对象,或者“Address”对象中的“Customer”,或者“Phone”对象中的“Customer”。下面是这一段的详细说明

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

基本的区别在于,提供程序允许将原语(非对象)、数组或回调函数的值设置到工厂声明的变量中,因此如果返回一个对象,它必须显式地声明和返回。

另一方面,服务只能用于将服务声明的变量设置为对象,因此可以避免显式地创建和返回对象,而另一方面,它允许使用this关键字。

或者简而言之,“提供者是一种更通用的形式,而服务仅限于对象”。

这里有更多的服务与工厂的例子,这些例子可能有助于了解它们之间的区别。基本上,一个服务调用了“new…”,它已经被实例化了。工厂不会自动实例化。

基本的例子

返回一个只有一个方法的类对象

下面是一个只有一个方法的服务:

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创建多个计数器。我们可以访问class变量来查看创建了多少个计数器:

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

有关简短的解释,请参阅https://stackoverflow.com/a/26924234/5811973。

详细解释请参考https://stackoverflow.com/a/15666049/5811973。

同样来自angularJs文档:

You can understand the difference with this analogy - Consider the difference between a normal function that will return some value and constructor function that will get instantiated using new keyword.So creating factory is just similar to create normal function that will return some value(primitive or an object) whereas creating service is like creating constructor function(OO class) of which we can create instance using new keyword. The only thing to notice is here is that when we use Service method to create services it will automatically create instance of it using dependency injection mechanism supported by AngularJS