我已经看到angular.factory()和angular.service()都用于声明服务;但是,我在官方文档中的任何地方都找不到angular.service

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

评论

关于服务与工厂的混淆可能重复

我搜索了“ [angularjs]服务工厂”,但我也想起已经有一个问题(因为我曾想过自己写这个/这个问题)。

在搜索中,方括号是否表示标签?

@Jacob方括号正在缩小搜索范围。 [angularjs]指令-将搜索“指令”以查找已经用angularjs标记的问题。

@Mahbub换句话说,“是” :)

#1 楼

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


直到我以这种方式将其付诸实践之前,我一直无法解决这个问题:
服务:您编写的函数将是新版本:
  myInjectedService  <----  new myServiceFunction()

Factory:您编写的函数(构造函数)将被调用:
  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(),您可以更轻松地管理对象集合。)

还有一件事,它们都是Singletons ...
请记住,在两种情况下,角度都有助于您管理一个单身人士。无论您在何处或多少次注入服务或功能,都将获得对相同对象或功能的相同引用。 (除了工厂何时仅返回数字或字符串之类的值。在这种情况下,您将始终获得相同的值,但没有引用。)

评论


称它为对象构造函数比使用Newable更好吗?

– marksyzm
2014年5月15日在11:21

@Hugo,我在演示,您可以用两者有效地完成相同的事情,只是语法会有所不同。

–吉尔·伯曼(Gil Birman)
2014年7月21日在4:19

我不确定我是否必须先阅读几次,才能确定服务和工厂之间的区别

–毁灭者DMac
2014年12月15日17:37

我们已经有一个动词说“ to new”,它是“ instantiate”。仅供参考。 :)

–sscarduzio
15年1月27日在16:35

工厂是被调用的函数,因此它们可以返回任何内容。另一方面,服务是通过新的fn()由angular实例化的,因此它们必须返回一个实例。

–吉尔·伯曼(Gil Birman)
15年4月8日在18:28

#2 楼

简单地说..



 const user = {
  firstName: 'john'
};

// Factory
const addLastNameFactory = (user, lastName) => ({
  ...user,
  lastName,
});

console.log(addLastNameFactory(user, 'doe'));

// Service
const addLastNameService = (user, lastName) => {
  user.lastName = lastName; // BAD! Mutation
  return user;
};

console.log(addLastNameService(user, 'doe')); 




评论


杜德,谢谢。并非其他答案的详细信息无效,但有时您需要10秒版本。

–R Claven
2014年3月24日在7:16

只是让服务函数什么都不返回。 this.name = ...足以表明它正在公开一个API。

–pixelbits
2014-09-22 21:08



但是,如果您确实返回并反对,它将使用它代替它。 jsfiddle.net/Ne5P8/1221

– MrB
2014年10月4日,下午1:32

@MrB,这是正常的JavaScript功能,并非特定于Angular或此问题的上下文。

– Om Shankar
2014年12月10日20:29在

@Om Shankar,上面的答案表明,区别在于此对象与返回对象的使用。我向我展示了“ THIS”是将与服务一起使用的默认值,但是,如果您返回一个值,它将几乎像工厂一样工作。但是,另一方面,工厂似乎要求返回值,否则会发生错误-(在此示例中显示-jsfiddle.net/hmoc0q3v/1)。

– MrB
2014-12-11 23:03



#3 楼

主要区别如下:

服务

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

结果:当将serviceName声明为可注入参数时,将为您提供实例传递给module.service的函数的用法。

用法:可用于共享实用程序函数,这些函数只需将( )附加到注入的函数引用中即可调用。也可以与injectedArg.call( this )或类似版本一起运行。

要素

module.factory( 'factoryName', function );

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

用法:对于返回“类”函数很有用,然后可以对其进行新的创建实例。

这里是使用服务和工厂的示例。阅读有关AngularJS Service vs Factory的更多信息。

您还可以查看AngularJS文档以及有关服务vs工厂的关于stackoverflow的类似问题。

评论


我不同意您使用工厂的示例。服务和工厂(假设返回了一个函数。它可能只是一个值或一个对象)都可以被更新。实际上,由于为您提供了功能实例,因此服务是唯一可以保证是新的选择。我要说的是,在服务上使用FACTORY的好处是,它允许对属性的访问进行某些控制-私有和公共本身,而服务的所有属性本质上都是公开的。而且我将提供者视为工厂的工厂-只有它可以在配置时注入和配置。

–提请R
2013年9月9日23:53



@DrewR感谢您的评论,我找到了一个使用工厂的公共和私有方法的很好的例子:stackoverflow.com/a/14904891/65025

– edzillion
2013年9月16日19:37在

实际上,我必须同意@DrewR。我以前曾经使用过工厂来返回对象,但是老实说,这时始终使用$ providers可能是值得的。

– jedd.ahyoung
2014年3月24日在2:48

服务是自动实例化构造函数的,对吗?

–Martian2049
16年8月21日在13:57

@DrewR-从我的理解来看,的确可以从服务中获得与工厂一样的可实现的新效果,但这并不意味着要这样做。它的主要目标是当您只想返回一些实用程序对象并为此提供更合适的语法时,您只需在服务中编写this.myFunc = function(){}(可避免编写代码来创建对象,例如您必须与工厂有关)。

– BornToCode
17 Mar 9 '17 at 9:03

#4 楼

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)使用服务时,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。_finalUrl是我们最终要使用的完整URL ll调用iTunes makeUrl是一个函数,它将创建并返回我们的
iTunes友好URL。

现在我们的帮助器/私有变量和函数已经到位,让我们向“服务”对象添加一些属性。无论我们使用哪种“服务”,只要将“ myFactory”传递给任何控制器,我们都可以直接使用。

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

下面的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正在返回承诺,因此我们可以使用.then()方法,并且仅在iTunes数据满足承诺后,才设置$ scope.data.artistData。您会注意到我们的控制器非常“薄”。我们所有的逻辑和持久数据都位于我们的服务中,而不是我们的控制器中。
2)服务
也许在创建服务时要知道的最大事情就是使用“ new”关键字实例化了它。对于您的JavaScript专家来说,这应该为您提供代码本质的重要提示。对于您中JavaScript知识有限的人,或者对“ new”关键字的实际功能不太熟悉的人,请查看一些JavaScript基础知识,这些基础知识最终将帮助我们理解服务的性质。

要真正看到使用'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中创建服务应该更容易理解。

创建服务时要了解的最大事情是知道服务已使用“ new”关键字实例化。将这些知识与上面的示例相结合,您现在应该认识到,您将把属性和方法直接附加到“ 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;
  }

});


现在就像在我们的工厂中一样,无论我们将myService传递给哪个控制器,都可以使用setArtist,getArtist和callItunes。这是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);
      })
  }
});


就像我之前提到的,一旦您真正了解“新”功能之后,服务与Angular的工厂几乎相同。

评论


您可能需要直接提供指向博客的链接。 tylermcginnis.com/angularjs-factory-vs-service-vs-provider我发现它更容易阅读。

–泰勒·科利尔(Tyler Collier)
2014年5月22日23:09

在这里重复您的博客没什么错,但是我同意那是一篇很烂的博客文章。

–R Claven
2014年5月28日0:32

对每个人在幕后所做的事情进行了详细的详细说明,但仍然不清楚为什么以及何时选择在工厂上使用服务。换句话说,相对于工厂返回的对象,我什么时候更喜欢使用更新的对象。我认为这是最大的困惑。

–demisx
2014年9月15日下午3:30

基本上,如果要创建到远程服务的持久连接(如示例中提到的iTunes API)并具有恒定连接(连接状态,呼叫历史记录,数据存储),则可以使用Factory。如果将其实现为服务,那么每次您希望从API中获得某些东西时,您都将重新创建连接,并且实际上无法在其中存储任何内容。因为每次重新创建服务时,都会得到一个空白/默认对象。

– Meki
2014年11月6日,11:23

我认为这是不对的,@ Aznim。就像其他人所说的,两者都提供单例。

–加密病毒
2015年5月10日,0:43

#5 楼

线索就是名称

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

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

服务用于实现服务模式

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

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

例如,这是一个Github服务。它知道如何与Github交谈。它了解网址和方法。我们可以将其注入到控制器中,它将生成并返回一个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”,该“ this”将指向正在构造的对象。

为了说明这一点,这里是使用服务和工厂:

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


评论


很好的解释,谢谢!在工厂样本代码中也有一种类型,其中Author writer参数应为Person。

– mikhail-t
2015年4月9日15:31

谢谢@ mik-T,我修复了错字。

–超级照明
2015年4月9日在20:33

您对服务模式的使用不正确-这应该是工厂。如果调用.factory()而不是.service(),则会看到它的工作原理完全相同。服务模式旨在提供一个构造函数,而不是一个返回新对象的函数。 Angular(有效地)在构造函数上调用“ new”。服务起作用的唯一原因是,如果在返回对象的构造函数上调用“ new”,则实际上是取回了返回的对象,而不是构造的对象。而且工厂可以用来创建您想要的任何东西,而不仅仅是模型。

–丹金
2015年8月6日15:34



#6 楼

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

要记住的关键是,每个都是另一种特殊情况。链中的每个特例都使您可以用更少的代码来做相同的事情。每个人也都有一些其他限制。

要决定何时使用哪个,您只需看哪个就可以用更少的代码来完成所需的工作。这是一张图像,说明它们之间的相似之处:



有关逐步详细的完整信息和使用时间的快速参考,您可以访问博客文章。我从以下图片中获得了这张图片:

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

评论


@jacob可能是这样,但是我认为不仅要何时使用它们,而且它们实质上都是同一事物的变体的整体概念很重要。

–路易斯·佩雷斯(Luis Perez)
2015年12月10日18:22

@LuisPerez指向您的博客的链接和解释其区别的视频非常棒。通过视频中的示例更容易理解:)

– Alin Ciocan
16年7月29日在7:10

#7 楼

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语句的情况下隐式返回构造的对象(在后一种情况下,您返回的对象将被创建并缓存,类似于工厂)。

–加密病毒
2015年5月10日,0:45

我认为您会误解它...当我说return时,我的意思是从服务功能实现的角度

–pixelbits
2015年5月10日在2:08



您确定工厂也是单一城镇吗?

–Martian2049
16年11月25日在1:28

#8 楼

我花了一些时间试图找出区别。

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

#9 楼

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

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


如果出于某种原因关心实例化服务的声明类型-如果使用服务模式,则构造函数将是新服务的类型。
如果您已经在其他地方使用了构造函数,并且也希望将其用作服务(尽管如果想向其中注入任何东西,可能用处不大!)。

可以说,从语法的角度来看,服务模式是创建新对象的一种更好的方法,但是实例化的代价也更高。其他人指出,angular使用“ new”来创建服务,但这不是真的-它无法做到这一点,因为每个服务构造函数都有不同数量的参数。 angular的实际作用是在内部使用工厂模式来包装构造函数。然后,它会执行一些巧妙的操作来模拟javascript的“新”运算符,并使用可变数量的可注入参数来调用构造函数-但是,如果您直接使用工厂模式,则可以省去此步骤,从而稍微提高了效率代码。

评论


服务比工厂更有效地构建,因为工厂使用相对昂贵的闭包,并且服务(类)可以利用原型。

–雅各布
15年8月6日在15:39

@jacob不确定您对闭包的含义吗?工厂只是一个返回对象的函数。仅在返回的对象需要“私有”状态时才需要使用闭包。如果使用构造函数(服务),则仍然必须做同样的事情。尽管您仍然可以在工厂中做到这一点,但我还是保留了原型的观点。

–丹金
2015年8月6日在16:29



函数MyFactory(dep1){var $$ foo ='bar',factory = {}; Object.defineProperties(factory.prototype,{foo:{value:$$ foo}});返回工厂; }函数MyService(dep1){var $$ foo ='bar'; Object.defineProperties(MyService.prototype,{foo:{value:$$ foo}}); }尽管MyFactory和MyService都使用原型,但是MyFactory仍然必须构造要返回的对象,因此对性能造成了影响。在两个示例中,它们都具有私有属性,但是在MyService中,性能相对没有差异。

–雅各布
15年8月6日在17:40

对我来说,区别在于我是否要直接使用工厂而不使用方法:MyFactory(someArgument)(例如$ http())。对于服务,这是不可能的,因为您将引用构造函数:MyService(someArgument)。

–雅各布
2015年8月6日在17:42



关于对象构造时间,我真的看不到factory = {}对性能有何影响,不止是JavaScript在调用构造函数时为您初始化“ this”?而且我认为,当将构造函数包装在工厂中然后为了模拟“新”而不得不跳过箍圈时,更大的性能损失将出现在角度方面,以便可以注入依赖项。

–丹金
15年8月6日在18:14