[译]AngularJS Service vs Factory - Once and for all
原文: http://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html
Service和Factory有什么不同,我应该使用哪个?
这篇文章将讲解service和factory的不同之处,为什么我们喜欢service多过于factory.
Service和Factory的不同之处
在AngularJS中service和factory有什么不同? 我们可以这样定义一个service:
app.service('MyService', function () { this.sayHello = function () { console.log('hello'); }; });
.service()
是我们module的一个方法。 有两个参数,第一个参数是服务名,第二个参数是一个function. 可以把Service注入到其他的component中,如controller, directive, filters. 注入方法如下:
app.controller('AppController', function (MyService) { MyService.sayHello(); // logs 'hello' });
好了,看看factory是如何做同样的事情的:
app.factory('MyService', function () { return { sayHello: function () { console.log('hello'); }; } });
.factory()
同样是我们module的一个方法,有两个参数,第一个是factory名,第二个是一个function. 同样factory也可以注入到其他components中. 那么他的不同之处在哪呢?
可以看到在factory中我们没有使用 this
, 而是返回一个对象字面量. 为什么这样?因为,service是一个构造函数factory不是. 所以我们在factory的funtion中要显示的返回一个对象.
来看看AngularJS的源代码中的factory函数是怎样的:
function factory(name, factoryFn, enforce) { return provider(name, { $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn }); }
factory接收一个name, 和factory函数,返回一个同名的provider, $get
是我们的factory函数. 当你获取一个注入,会调用$get()方法向相应的provider请求一个service的实例. 这就是为什么创建provider的时候需要有$get()方法.
换而言之, 当注入MyService
时, 后面究竟发生了什么呢:
MyServiceProvider.$get(); // 返回service的实例
现在看看service函数在AngularJS的源代码中是怎么样的:
function service(name, constructor) { return factory(name, ['$injector', function($injector) { return $injector.instantiate(constructor); }]); }
从代码中看得出来,当调用service()的时候实际上最后调用了factory(). 但是没有直接把service的构造函数传给factory. 而是传递了一个依赖injector的函数,通过这个injector去实例化. 简单的说: service调用了预定义的factory, 最后调用相应的provider的$get()方法. $injector.instantiate()
方法最终调用Object.create(),参数为构造函数
. 这就是为什么我们要在service里面使用this.
不论我么使用 service()
还是 factory()
, 最终都是一个factory,然后这个factory去调用provider.
使用哪一个?
“serivce和factory的不同如下:”
app.service('myService', function() { // service是一个构造函数 this.sayHello = function(name) { return "Hi " + name + "!"; }; }); app.factory('myFactory', function() { // factory返回一个对象 return { sayHello : function(name) { return "Hi " + name + "!"; } } });
是的service是一个构造函数, 然后我们一样可以在这个构造函数中返回对象字面量. 事实上, 在javascript中构造函数可以返回任何你想返回的东西. 所以我们把service写得和factory一样:
app.service('MyService', function () { // 我们可以在这加入其它的代码 return { sayHello: function () { console.log('hello'); }; } });
现在factory和service的写法已经一样了. 问题是: 我们该使用哪一个呢?
Service能让我们使用ES6的class
在ES6中我们可以这样定义service:
class MyService { sayHello() { console.log('hello'); } } app.service('MyService', MyService);
ES6 class和ES5中的构造函数是一回事.