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

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

演示的示例代码:

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?

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


当前回答

非常简单:

.service——注册的函数将作为构造函数被调用(又名'newed')

.factory注册的函数将被作为一个简单函数调用

两者都被调用一次,导致一个单例对象被注入到应用程序的其他组件中。

其他回答

对我来说,当我意识到它们都以相同的方式工作时,我得到了启示:通过运行一次,存储它们得到的值,然后在通过依赖注入引用时吐出相同的存储值。

假设我们有:

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

这三者的区别在于:

A的存储值来自运行fn,换句话说:fn() B的存储值来自于new fn,换句话说:new fn() C的存储值来自于首先通过new fn获得一个实例,然后运行实例的$get方法

这意味着,在angular内部有一个类似缓存对象的东西,它的每次注入的值只被赋值一次,当它们第一次被注入时,并且在:

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

这就是为什么我们在服务中使用This,并定义一个This。$get在供应商。

多亏了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依赖注入系统。它是非常灵活的,可以 包含复杂的创建逻辑。因为工厂是正规的 函数,也可以利用新的词法作用域来实现 模拟“私有”变量。这很有用,因为我们可以隐藏 给定服务的实现细节。”

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

这将是理解服务Vs工厂Vs提供商的最佳和简短的答案

来源:https://groups.google.com/forum/ !味精/角度/ 56 sdorweoqg / HuZsOsMvKv4J

这里本说的演示http://jsbin.com/ohamub/1/edit?html,output

“代码中有一些注释说明了主要的差异,但我将在这里展开一点。作为说明,我只是在思考这个问题,所以如果我说错了什么,请告诉我。

服务

语法:模块。service('serviceName',函数);

结果:当将serviceName声明为可注入参数时,你将得到传递给module.service的实际函数引用。

使用方法:可以通过简单地将()附加到注入的函数引用来共享有用的实用程序函数。也可以用injectedArg运行。调用(这个)或类似的方法。

工厂

语法:模块。factory('factoryName',函数);

结果:当将factoryName声明为一个可注入参数时,你将得到通过调用传递给module.factory的函数引用返回的值。

用法:可能用于返回一个'class'函数,然后可以重新创建实例。

供应商

语法:模块。provider('providerName',函数);

结果:当将providerName声明为一个可注入参数时,您将获得通过调用传递给module.provider的函数引用的$get方法返回的值。

用途:可能用于返回一个'类'函数,然后可以重新创建实例,但在注入之前需要某种配置。也许对跨项目可重用的类有用?这一点还不太清楚。” 本

对于工厂,你实际上是在工厂内部创建一个对象并返回它。 对于该服务,您只有一个使用this关键字进行定义的标准函数 函数。 在提供程序中,你定义了一个$get,它可以用来获取返回的对象 数据。