ChatGPT解决这个技术问题 Extra ChatGPT

angular.service 与 angular.factory

我见过 angular.factory()angular.service() 都用于声明服务;但是,我 cannot find angular.service 在官方文档中的任何地方。

这两种方法有什么区别?哪个应该用于什么(假设他们做不同的事情)?

我搜索了“[angularjs] 服务工厂”,但我也记得已经有一个关于它的问题(因为我曾经想过自己写那个/这个问题)。
在搜索中,方括号是否表示标签?
@Jacob 方括号正在缩小您的搜索范围。 [angularjs] 指令——将搜索“指令”以查找已用 angularjs 标记的问题。
@Mahbub 换句话说,“是的”:)

C
Community
  angular.service('myService', myServiceFunction);
  angular.factory('myFactory', myFactoryFunction);

在我这样说之前,我很难理解这个概念:

服务:您编写的功能将是新的:

  myInjectedService  <----  new myServiceFunction()

工厂:将调用您编写的函数(构造函数):

  myInjectedFactory  <---  myFactoryFunction()

你用它做什么取决于你,但有一些有用的模式......

比如写一个服务函数来暴露一个公共的API:

function myServiceFunction() {
  this.awesomeApi = function(optional) {
    // calculate some stuff
    return awesomeListOfValues;
  }
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();

或者使用工厂函数来公开公共 API:

function myFactoryFunction() {
  var aPrivateVariable = "yay";

  function hello() {
    return "hello mars " + aPrivateVariable;
  }
  
  // expose a public API
  return {
    hello: hello
  };
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.hello = myInjectedFactory.hello();

或者使用工厂函数返回构造函数:

function myFactoryFunction() {
    return function() {
        var a = 2;
        this.a2 = function() {
            return a*2;
        };
    };
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();

用哪一个?...

你可以用两者来完成同样的事情。但是,在某些情况下,工厂为您提供了更多的灵活性来创建具有更简单语法的可注入对象。这是因为 myInjectedService 必须始终是对象,而 myInjectedFactory 可以是对象、函数引用或任何值。例如,如果您编写了一个服务来创建一个构造函数(如上面的最后一个示例),则必须像这样实例化它:

var myShinyNewObject = new myInjectedService.myFunction()

可以说这比这更不可取:

var myShinyNewObject = new myInjectedFactory();

(但您首先应该警惕使用这种类型的模式,因为控制器中的 new 对象会创建难以跟踪的依赖项,这些依赖项很难模拟以进行测试。最好有一个服务为您管理对象集合,而不是随意使用 new()。)

还有一件事,他们都是单身人士......

还要记住,在这两种情况下,角度都可以帮助您管理单例。无论您在何处或多少次注入您的服务或函数,您都将获得对同一对象或函数的相同引用。 (工厂只返回一个数字或字符串之类的值除外。在这种情况下,您将始终获得相同的值,但不是引用。)


将其称为对象构造函数会比 Newable 更好吗?
@Hugo,我在证明你可以用两者有效地完成同样的事情,只是语法会有所不同。
在我确信两者都是必要的之前,我不确定我必须阅读多少次关于服务和工厂之间的区别
我们已经有了一个动词来表示“to new”,它是“instantiate”。仅供参考。 :)
工厂是被调用的函数,所以它们可以返回任何东西。另一方面,服务是通过 Angular 通过 new fn() 实例化的,因此它们必须返回一个实例。
K
Kirk Strobeck

简单的说 ..

常量用户 = { 名字:'约翰' }; // 工厂 const addLastNameFactory = (user, lastName) => ({ ...user, lastName, }); console.log(addLastNameFactory(user, 'doe')); // 服务 const addLastNameService = (user, lastName) => { user.lastName = lastName; // 坏的!突变返回用户; }; console.log(addLastNameService(user, 'doe'));


伙计,谢谢。并不是说其他答案的详细信息无效,但有时您需要 10 秒版本。
只需让服务功能不返回任何内容。 this.name = ... 足以表明它正在公开一个 API。
但是,如果您确实返回并反对,它将使用它而不是 this。 jsfiddle.net/Ne5P8/1221
@MrB,这是一个普通的 JavaScript 功能,不是特定于 Angular 或这个问题的上下文。
@Om Shankar,上面的答案表明区别在于 this 与返回的对象的使用。我展示了“THIS”是服务的默认值,但是如果你返回一个值,它的行为几乎就像一个工厂。然而,另一方面,工厂似乎需要返回值,否则将发生错误 - (在此示例中显示 - jsfiddle.net/hmoc0q3v/1)。
C
Community

以下是主要区别:

服务

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

结果:将 serviceName 声明为可注入参数时,您将获得传递给 module.service函数实例

用法:对于共享实用程序函数很有用,只需将 ( ) 附加到注入的函数引用即可调用。也可以使用 injectedArg.call( this ) 或类似方法运行。

工厂

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

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

用法:对于返回一个“类”函数可能很有用,然后可以新建该函数以创建实例。

这是example using services and factory。阅读有关 AngularJS Service vs Factory 的更多信息。

您还可以查看 stackoverflow confused about service vs factory 上的 AngularJS documentation 和类似问题。


我不同意您对工厂的示例用法。服务和工厂(假设返回了一个函数。它可能只是一个值或一个对象)都可以是新的。事实上,服务是唯一可以保证是新的选项,因为您提供了一个函数实例。我会说使用 FACTORY 而不是 SERVICE 的好处是它允许对属性的访问进行一些控制 - 私有和公共本身,而服务的所有属性本质上都是暴露的。我认为提供者是工厂的工厂——只有它在配置时是可注入和可配置的。
@DrewR 感谢您的评论,我找到了使用工厂的公共和私有方法的一个很好的例子:stackoverflow.com/a/14904891/65025
实际上,我必须同意@DrewR 在这一点上。我以前使用过工厂来返回对象,但老实说,在这一点上,一直使用 $providers 可能是值得的。
服务是自动实例化构造函数,对吗?
@DrewR - 据我了解,您确实可以像使用工厂一样从服务中获得相同的新效果,但这不是它的本意。它的主要目标是当您只想返回一些实用程序对象并为此提供更合适的语法时 - 您可以简单地在您的服务中编写 this.myFunc = function(){} (使您免于编写代码来创建对象,就像您必须做的那样与工厂)。
Z
Zanon

TL;DR 1) 当您使用工厂时,您创建一个对象,向其添加属性,然后返回相同的对象。当您将此工厂传递给您的控制器时,对象上的这些属性现在将通过您的工厂在该控制器中可用。

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory('myFactory', function(){
  var _artist = 'Shakira';
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});

2) 当你使用 Service 时,Angular 会在幕后使用 'new' 关键字来实例化它。因此,您将向“this”添加属性,服务将返回“this”。当您将服务传递到您的控制器时,“this”上的那些属性现在将通过您的服务在该控制器上可用。

app.controller('myServiceCtrl', function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service('myService', function(){
  var _artist = 'Nelly';
  this.getArtist = function(){
    return _artist;
  }
});

非 TL;DR

1) 工厂工厂是最流行的创建和配置服务的方式。没有什么比 TL;DR 所说的更多了。您只需创建一个对象,为其添加属性,然后返回相同的对象。然后,当您将工厂传递给您的控制器时,对象上的这些属性现在将通过您的工厂在该控制器中可用。下面是一个更广泛的示例。

app.factory('myFactory', function(){
  var service = {};
  return service;
});

现在,当我们将“myFactory”传递给我们的控制器时,我们附加到“服务”的任何属性都将可供我们使用。

现在让我们在回调函数中添加一些“私有”变量。这些将无法从控制器直接访问,但我们最终会在“服务”上设置一些 getter/setter 方法,以便能够在需要时更改这些“私有”变量。

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
   _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK';
    return _finalUrl
  }

  return service;
});

在这里,您会注意到我们没有将这些变量/函数附加到“服务”。我们只是创建它们以便以后使用或修改它们。

baseUrl 是 iTunes API 需要的基本 URL

_artist 是我们要查找的艺术家

_finalUrl 是我们将调用 iTunes 的最终且完全构建的 URL makeUrl 是一个将创建并返回我们的 iTunes 友好 URL 的函数。

现在我们的辅助/私有变量和函数已经到位,让我们为“服务”对象添加一些属性。无论我们在“服务”上放置什么,我们都可以直接在我们将“myFactory”传入的任何控制器中使用。

我们将创建简单地返回或设置艺术家的 setArtist 和 getArtist 方法。我们还将创建一个方法,该方法将使用我们创建的 URL 调用 iTunes API。此方法将返回一个承诺,一旦数据从 iTunes API 返回,该承诺将履行。如果你没有太多在 Angular 中使用 Promise 的经验,我强烈建议你深入研究它们。

下面的 setArtist 接受一个艺术家并允许您设置艺术家。 getArtist 返回艺术家 callItunes 首先调用 makeUrl() 以构建我们将在 $http 请求中使用的 URL。然后它设置一个promise对象,用我们的最终url发出一个$http请求,然后因为$http返回一个promise,我们可以在请求之后调用.success或.error。然后我们用 iTunes 数据解决我们的承诺,或者我们拒绝它并显示一条消息说“有一个错误”。

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

现在我们的工厂已经完工。我们现在可以将“myFactory”注入任何控制器,然后我们就可以调用我们附加到服务对象的方法(setArtist、getArtist 和 callItunes)。

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

在上面的控制器中,我们注入了“myFactory”服务。然后,我们在 $scope 对象上设置来自“myFactory”数据的属性。上面唯一棘手的代码是如果您以前从未处理过承诺。因为 callItunes 返回了一个 Promise,所以我们可以使用 .then() 方法,并且只有在我们的 Promise 与 iTunes 数据一起实现时才设置 $scope.data.artistData。您会注意到我们的控制器非常“薄”。我们所有的逻辑和持久数据都位于我们的服务中,而不是我们的控制器中。 2) 服务 在处理创建服务时要知道的最重要的事情可能是它是用“新”关键字实例化的。对于您的 JavaScript 专家,这应该会给您一个关于代码性质的重要提示。对于那些 JavaScript 背景有限或不太熟悉“new”关键字实际作用的人,让我们回顾一些 JavaScript 基础知识,这些基础知识最终将帮助我们理解服务的本质。

要真正看到使用“new”关键字调用函数时发生的变化,让我们创建一个函数并使用“new”关键字调用它,然后让我们展示解释器在看到“new”关键字时会做什么。最终结果将是相同的。

首先让我们创建我们的构造函数。

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

这是一个典型的 JavaScript 构造函数。现在,每当我们使用“new”关键字调用 Person 函数时,“this”都会绑定到新创建的对象。

现在让我们在 Person 的原型上添加一个方法,这样它就可以在我们的 Person“类”的每个实例上使用。

Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}

现在,因为我们将 sayName 函数放在原型上,所以 Person 的每个实例都可以调用 sayName 函数以提醒该实例的名称。

现在我们的原型上已经有了 Person 构造函数和 sayName 函数,让我们实际创建一个 Person 实例然后调用 sayName 函数。

var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

因此,用于创建 Person 构造函数、向其原型添加函数、创建 Person 实例,然后在其原型上调用函数的所有代码看起来像这样。

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

现在让我们看看在 JavaScript 中使用“new”关键字时实际发生了什么。您应该注意到的第一件事是,在我们的示例中使用 'new' 之后,我们可以在 'tyler' 上调用方法(sayName),就好像它是一个对象一样——因为它是。所以首先,我们知道我们的 Person 构造函数正在返回一个对象,无论我们是否可以在代码中看到它。其次,我们知道因为我们的 sayName 函数位于原型上而不是直接位于 Person 实例上,所以 Person 函数返回的对象必须在查找失败时委托给它的原型。更简单地说,当我们调用 tyler.sayName() 时,解释器会说“好的,我要查看我们刚刚创建的 'tyler' 对象,找到 sayName 函数,然后调用它。等一下,我在这里看不到——我看到的只是名字和年龄,让我检查一下原型。是的,看起来它在原型上,让我称之为。”。

下面是如何思考“new”关键字在 JavaScript 中实际作用的代码。它基本上是上一段的代码示例。我已经放置了“解释器视图”或解释器在注释中查看代码的方式。

var Person = function(name, age){
  //The line below this creates an obj object that will delegate to the person's prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets 'this' to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

现在了解了 'new' 关键字在 JavaScript 中的真正作用,在 Angular 中创建服务应该更容易理解。

创建服务时要了解的最重要的事情是知道服务是使用“新”关键字实例化的。将这些知识与我们上面的示例相结合,您现在应该认识到您将直接将属性和方法附加到“this”,然后将从服务本身返回。让我们来看看这个实际操作。

与我们最初对 Factory 示例所做的不同,我们不需要创建一个对象然后返回该对象,因为就像之前多次提到的那样,我们使用了 'new' 关键字,因此解释器将创建该对象,让它委托给它是原型,然后将其返回给我们,而无需我们进行工作。

首先,让我们创建我们的“私有”和辅助函数。这看起来应该很熟悉,因为我们对我们的工厂做了完全相同的事情。我不会在这里解释每一行的作用,因为我在工厂示例中做过,如果您感到困惑,请重新阅读工厂示例。

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

现在,我们将把控制器中可用的所有方法附加到“this”。

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

现在就像在我们的工厂中一样,setArtist、getArtist 和 callItunes 将在我们将 myService 传递到的任何控制器中可用。这是 myService 控制器(与我们的工厂控制器几乎完全相同)。

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

就像我之前提到的,一旦你真正理解了“新”的作用,Services 几乎与 Angular 中的工厂相同。


您可能想直接提供指向您博客的链接。 tylermcginnis.com/angularjs-factory-vs-service-vs-provider 我发现它更容易阅读。
在这里重复你的博客没什么错,但我同意这是一篇很好的博客文章。
很好地详细解释了每个人在幕后所做的事情,但仍然不清楚为什么以及何时有人选择使用服务而不是工厂。换句话说,我什么时候更喜欢新的对象而不是工厂返回的对象。我认为这是最大的困惑。
基本上,如果您想创建与远程服务的持久连接,例如示例中提到的具有恒定连接(连接状态、调用历史、数据存储)的 iTunes API,您可以使用 Factory。如果您将其实现为服务,那么每次您想要从 API 中获取某些内容时,您都将重新创建连接,并且无法真正在其中存储任何内容。因为每次重新创建服务时,都会得到一个空白/默认对象。
我不认为这是正确的,@Aznim。正如其他人所说,两者都提供单例。
s
superluminary

线索就在名字里

服务和工厂彼此相似。两者都会产生一个可以注入其他对象的单例对象,因此通常可以互换使用。

它们旨在在语义上用于实现不同的设计模式。

服务用于实现服务模式

服务模式是一种将您的应用程序分解为逻辑一致的功能单元的模式。一个示例可能是 API 访问器或一组业务逻辑。

这在 Angular 中尤为重要,因为 Angular 模型通常只是从服务器中提取的 JSON 对象,因此我们需要在某个地方放置我们的业务逻辑。

以 Github 服务为例。它知道如何与 Github 对话。它知道 url 和方法。我们可以将它注入到控制器中,它会生成并返回一个 Promise。

(function() {
  var base = "https://api.github.com";

  angular.module('github', [])
    .service('githubService', function( $http ) {
      this.getEvents: function() {
        var url = [
          base,
          '/events',
          '?callback=JSON_CALLBACK'
        ].join('');
        return $http.jsonp(url);
      }
    });
  )();

工厂实现工厂模式

另一方面,工厂旨在实现工厂模式。一种工厂模式,我们使用工厂函数来生成对象。通常我们可能会使用它来构建模型。这是一个返回 Author 构造函数的工厂:

angular.module('user', [])
  .factory('User', function($resource) {
    var url = 'http://simple-api.herokuapp.com/api/v1/authors/:id'
    return $resource(url);
  })

我们会像这样使用它:

angular.module('app', ['user'])
  .controller('authorController', function($scope, User) {
    $scope.user = new User();
  })

请注意,工厂也返回单例。

工厂可以返回一个构造函数

因为工厂只是返回一个对象,所以它可以返回您喜欢的任何类型的对象,包括构造函数,正如我们在上面看到的。

工厂返回一个对象;服务是新的

另一个技术差异是服务和工厂的组成方式。将新建一个服务函数来生成对象。工厂函数将被调用并返回对象。

服务是新的构造函数。

工厂被简单地调用并返回一个对象。

这意味着在服务中,我们附加到“this”,在构造函数的上下文中,它将指向正在构建的对象。

为了说明这一点,下面是使用服务和工厂创建的同一个简单对象:

angular.module('app', [])
  .service('helloService', function() {
    this.sayHello = function() {
      return "Hello!";
    }
  })
  .factory('helloFactory', function() {
    return {
      sayHello: function() {
        return "Hello!";
      }
    }
  });

很好的解释,谢谢! Factories 示例代码中还有一个类型,其中 Author 注入器参数应为 Person
谢谢@mik-T,我修正了错别字。
您对服务模式的使用不正确 - 这应该是工厂。如果您调用 .factory() 而不是 .service() 您会发现它的工作原理完全相同。服务模式旨在提供构造函数,而不是返回新对象的函数。 Angular(有效地)在您的构造函数上调用“new”。您的服务工作的唯一原因是,如果您在返回对象的构造函数上调用“new”,您实际上会返回返回的对象而不是构造的对象。工厂可以用来创建任何你想要的东西,而不仅仅是模型。
L
Luis Perez

这里的所有答案似乎都与服务和工厂有关,这是有效的,因为这是被问到的。但同样重要的是要记住还有其他几个,包括 provider()value()constant()

要记住的关键是每个都是另一个的特殊情况。每个特殊情况都允许您用更少的代码做同样的事情。每一个也有一些额外的限制。

要决定何时使用哪个,您只需查看哪个允许您用更少的代码做您想做的事。这是一张图片,说明了它们的相似程度:

https://i.stack.imgur.com/CkdHl.png

有关何时使用每个的完整分步细分和快速参考,您可以访问我从中获得此图像的博客文章:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


@jacob 可能是这样,但我认为不仅何时使用它们,而且它们本质上都是同一事物的变体的总体概念是一个重要的概念。
@LuisPerez 指向您博客的链接和解释差异的视频真的很棒。使用视频中的这些示例更容易理解:)
p
pixelbits

app.factory('fn', fn) 与 app.service('fn',fn)

建造

对于工厂,Angular 将调用该函数来获取结果。它是被缓存和注入的结果。

 //factory
 var obj = fn();
 return obj;

对于服务,Angular 将通过调用 new 来调用构造函数。构造函数被缓存和注入。

  //service
  var obj = new fn();
  return obj;

执行

工厂通常返回一个对象字面量,因为返回值是注入控制器、运行块、指令等的内容

  app.factory('fn', function(){
         var foo = 0;
         var bar = 0;
         function setFoo(val) {
               foo = val;
         }
         function setBar (val){
               bar = val;
         }
         return {
                setFoo: setFoo,
                serBar: setBar
         }
  });

服务函数通常不返回任何内容。相反,它们执行初始化并公开功能。函数也可以引用“this”,因为它是使用“new”构造的。

app.service('fn', function () {
         var foo = 0;
         var bar = 0;
         this.setFoo = function (val) {
               foo = val;
         }
         this.setBar = function (val){
               bar = val;
         }
});

结论

在使用工厂或服务方面,它们都非常相似。它们被注入到控制器、指令、运行块等中,并以几乎相同的方式在客户端代码中使用。它们也是单例 - 这意味着在注入服务/工厂的所有位置之间共享相同的实例。

那么你应该更喜欢哪个?任何一个 - 它们是如此相似,以至于差异微不足道。如果您确实选择了另一个,请注意它们的构造方式,以便您可以正确实施它们。


服务函数不会“不返回任何东西”,如果您没有指定自己的 return 语句,它们会隐式返回构造的对象(在后一种情况下,您返回的对象将被创建和缓存,类似于工厂)。
我认为您误解了它...当我说返回时,我的意思是从服务功能实现的角度来看
你确定工厂也是单镇吗?
p
ps.

我花了一些时间试图找出差异。

而且我认为工厂函数使用模块模式,服务函数使用标准的java脚本构造函数模式。


D
Dan King

工厂模式更灵活,因为它可以返回函数和值以及对象。

恕我直言,服务模式没有太多意义,因为它所做的一切都可以像工厂一样轻松地完成。例外情况可能是:

如果您出于某种原因关心实例化服务的声明类型 - 如果您使用服务模式,那么您的构造函数将是新服务的类型。

如果您已经有一个在其他地方使用的构造函数,那么您也想将其用作服务(尽管如果您想向其中注入任何东西可能没有多大用处!)。

可以说,从语法的角度来看,服务模式是一种更好的创建新对象的方式,但实例化的成本也更高。其他人表示 Angular 使用“new”来创建服务,但这并不完全正确——它无法做到这一点,因为每个服务构造函数都有不同数量的参数。 Angular 实际上所做的是在内部使用工厂模式来包装您的构造函数。然后它会做一些巧妙的玩弄游戏来模拟 javascript 的“new”操作符,使用可变数量的可注入参数调用您的构造函数 - 但如果您直接使用工厂模式,则可以省略这一步,从而略微提高您的效率代码。


服务比工厂更高效,因为工厂使用相对昂贵的闭包,服务(类)可以利用原型。
@jacob 不确定你对闭包的意思是什么?工厂只是一个返回对象的函数。如果您返回的对象需要“私有”状态,您只需要使用闭包。如果您使用构造函数(服务),您仍然需要做同样的事情。不过,我同意您对原型的看法-尽管如果您愿意,您仍然可以在工厂中进行此操作。
function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; } function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); } 虽然 MyFactory 和 MyService 都使用原型,但 MyFactory 仍然需要构造返回的对象的性能。在这两个示例中,它们都有私有属性,但在 MyService 中相对没有性能差异。
对我来说,区别在于我是否想直接使用工厂而不使用方法:MyFactory(someArgument)(例如 $http())。这对于服务是不可能的,因为您将引用构造函数:MyService(someArgument)
在对象构造时,我真的不知道 factory = {} 是如何影响性能的,而不是 javascript 在调用构造函数时为您初始化“this”?而且我认为更大的性能影响在于角度方面,当它将您的构造函数包装在工厂中然后必须跳过箍以模拟“新”以便它可以注入您的依赖项。