angular.factory()とangular.service()の両方がサービスの宣言に使用されるのを見てきました。ただし、公式ドキュメントには angular.service
どこにもありません。
2つの方法の違いは何ですか?
何が何のために使われるべきですか?
angular.factory()とangular.service()の両方がサービスの宣言に使用されるのを見てきました。ただし、公式ドキュメントには angular.service
どこにもありません。
2つの方法の違いは何ですか?
何が何のために使われるべきですか?
回答:
angular.service('myService', myServiceFunction);
angular.factory('myFactory', myFactoryFunction);
このように考えるまで、このコンセプトに頭を抱えるのに苦労しました。
サービス:あなたが書く関数は新しくなります-
myInjectedService <---- new myServiceFunction()
ファクトリー:作成した関数(コンストラクター)が呼び出されます:
myInjectedFactory <--- myFactoryFunction()
それをどうするかはあなた次第ですが、いくつかの便利なパターンがあります...
function myServiceFunction() {
this.awesomeApi = function(optional) {
// calculate some stuff
return awesomeListOfValues;
}
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();
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()
wily-nillyを使うよりも。)
また、どちらの場合でも、angularはシングルトンの管理に役立ちます。サービスまたは関数を挿入する場所や回数に関係なく、同じオブジェクトまたは関数への同じ参照を取得します。(ファクトリーが数値や文字列のような値を返す場合を除いて。その場合、常に同じ値を取得しますが、参照は取得しません。)
new fn()
ため、インスタンスを返す必要があります。
簡単に言えば ..
// Service
service = (a, b) => {
a.lastName = b;
return a;
};
// Factory
factory = (a, b) => Object.assign({}, a, { lastName: b });
const fullName = { firstName: 'john' };
// Service
const lastNameService = (a, b) => {
a.lastName = b;
return a;
};
console.log(lastNameService(fullName, 'doe'));
// Factory
const lastNameFactory = (a, b) =>
Object.assign({}, a, { lastName: b })
console.log(lastNameFactory(fullName, 'doe'));
主な違いは次のとおりです。
構文: module.service( 'serviceName', function );
結果:serviceNameを注入可能な引数として宣言すると、に渡される関数のインスタンスが提供されますmodule.service
。
使用法:注入された関数参照に追加するだけで呼び出すことができるユーティリティ関数を共有するのに役立ち( )
ます。injectedArg.call( this )
または同様に実行することもできます。
構文: module.factory( 'factoryName', function );
結果:factoryNameを注入可能な引数として宣言すると、に渡される関数参照を呼び出すことによって返される値が提供されmodule.factory
ます。
使用法:インスタンスを作成するために新規作成できる「クラス」関数を返すのに役立ちます。
以下は、サービスとファクトリーの使用例です。AngularJS ServiceとFactoryの詳細を読んでください。
AngularJSのドキュメントや、サービスとファクトリーについて混乱しているstackoverflowに関する同様の質問を確認することもできます。
$providers
常に使用するだけの価値があるかもしれません。
this.myFunc = function(){}
サービスに書き込むだけです(コードを記述して、ファクトリで行う必要があるようなオブジェクトを作成する必要がなくなります)。 )。
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」をコントローラーに渡すと、「service」にアタッチしたすべてのプロパティを使用できるようになります。
次に、いくつかの「プライベート」変数をコールバック関数に追加しましょう。これらはコントローラーから直接アクセスできませんが、必要に応じてこれらの「プライベート」変数を変更できるように、最終的に「サービス」にいくつかのゲッター/セッターメソッドを設定します。
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;
});
ここで、これらの変数/関数を「サービス」にアタッチしていないことに気づくでしょう。後で使用または変更するために、単に作成しています。
ヘルパー/プライベート変数と関数が用意できたので、「サービス」オブジェクトにいくつかのプロパティを追加しましょう。「サービス」をどのように設定しても、「myFactory」を渡すどのコントローラーでも直接使用できます。
アーティストを返すか設定するだけのsetArtistメソッドとgetArtistメソッドを作成します。また、作成したURLでiTunes APIを呼び出すメソッドを作成します。このメソッドは、iTunes APIからデータが返されると満たされるpromiseを返します。Angularでプロミスを使用した経験があまりない場合は、プロミスについて深く学ぶことを強くお勧めします。
以下のsetArtistはアーティストを受け入れ、アーティストを設定できます。getArtistは、アーティストのcallItunesを返します。最初に、$ httpリクエストで使用するURLを作成するためにmakeUrl()を呼び出します。次に、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」サービスに注入しています。次に、「myFactory」のデータから取得した$ scopeオブジェクトにプロパティを設定します。上記の唯一のトリッキーなコードは、これまでに約束を扱ったことがない場合です。callItunesがpromiseを返すため、.then()メソッドを使用して、iTunesデータでpromiseが満たされた場合にのみ$ scope.data.artistDataを設定できます。コントローラーが非常に「薄い」ことに気づくでしょう。ロジックと永続データはすべて、コントローラーではなくサービスにあります。
2)サービス
おそらく、サービスの作成を処理する際に知っておくべき最大のことは、「新しい」キーワードでインスタンス化されるということです。JavaScriptの達人にとって、これはコードの性質に大きなヒントを与えるはずです。JavaScriptのバックグラウンドが限られている方や、「新しい」キーワードの実際の動作に慣れていない方のために、最終的にサービスの性質を理解するのに役立つ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()を呼び出すと、インタープリターは「OK、先ほど作成した '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;
}
});
これで、ファクトリと同様に、setServiceist、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);
})
}
});
前に述べたように、「新しい」機能を理解すると、サービスはAngularのファクトリとほぼ同じになります。
サービスと工場は互いに似ています。どちらも、他のオブジェクトに注入できるシングルトンオブジェクトを生成するため、しばしば同じ意味で使用されます。
これらは、異なるデザインパターンを実装するために意味的に使用されることを目的としています。
サービスパターンとは、アプリケーションが論理的に一貫した機能単位に分割されるパターンです。例としては、APIアクセサーやビジネスロジックのセットなどがあります。
Angularは通常、サーバーからプルされた単なるJSONオブジェクトであるため、Angularでこれは特に重要であり、ビジネスロジックを配置する場所が必要です。
以下は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();
})
工場もシングルトンを返すことに注意してください。
ファクトリはオブジェクトを返すだけなので、上記のように、コンストラクター関数を含め、任意のタイプのオブジェクトを返すことができます。
もう1つの技術的な違いは、サービスと工場の構成方法にあります。オブジェクトを生成するサービス関数が新しくなります。ファクトリ関数が呼び出され、オブジェクトを返します。
つまり、サービスでは、「this」に追加します。これは、コンストラクターのコンテキストでは、作成中のオブジェクトを指します。
これを説明するために、サービスとファクトリを使用して作成された同じ単純なオブジェクトを次に示します。
angular.module('app', [])
.service('helloService', function() {
this.sayHello = function() {
return "Hello!";
}
})
.factory('helloFactory', function() {
return {
sayHello: function() {
return "Hello!";
}
}
});
Author
ますPerson
。
ここでのすべての答えはサービスと工場に関するものであるように思われ、それが質問されていたのでそれは有効です。しかし、それはそこを含むいくつかの他の人があることを心に留めておくことも重要だprovider()
、value()
とconstant()
。
覚えておくべき重要な点は、それぞれが他の特殊なケースであることです。特別なケースごとに、同じことを少ないコードで実行できます。それぞれにいくつかの追加の制限があります。
どれを使用するかを決定するには、どれを使用するかを確認するだけで、少ないコードで目的の操作を実行できます。以下は、それらがどれほど類似しているかを示す画像です。
完全なステップごとの内訳とそれぞれをいつ使用するかのクイックリファレンスについては、この画像を取得したブログ投稿にアクセスできます。
建設
ファクトリーでは、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
}
});
通常、サービス関数は何も返しません。代わりに、初期化を実行して関数を公開します。関数は、「new」を使用して作成されているため、「this」を参照することもできます。
app.service('fn', function () {
var foo = 0;
var bar = 0;
this.setFoo = function (val) {
foo = val;
}
this.setBar = function (val){
bar = val;
}
});
結論
工場やサービスを使用することに関しては、どちらも非常によく似ています。それらは、コントローラー、ディレクティブ、実行ブロックなどに注入され、クライアントコードでほとんど同じ方法で使用されます。これらは両方ともシングルトンでもあります。つまり、同じインスタンスがサービス/ファクトリが注入されるすべての場所で共有されます。
それであなたはどちらを好むべきですか?どちらか-それらは非常に似ているため、違いは些細なものです。どちらか一方を選択する場合は、それらが適切に実装できるように、それらがどのように構築されるかに注意してください。
ファクトリパターンは、関数や値、オブジェクトを返すことができるため、より柔軟です。
サービスパターンIMHOには、工場で同じように簡単に実行できるすべての機能があるため、あまり意味がありません。例外は次のとおりです。
間違いなく、サービスパターンは構文の観点から新しいオブジェクトを作成するための少し優れた方法ですが、インスタンス化のコストも高くなります。他の人は、angularが「新規」を使用してサービスを作成することを示していますが、これは完全に真実ではありません。すべてのサービスコンストラクターが異なる数のパラメーターを持っているため、これを行うことはできません。angularが実際に行うことは、コンストラクター関数をラップするためにファクトリーパターンを内部で使用することです。次に、JavaScriptの「新しい」演算子をシミュレートする巧妙なジグザリーポケリーを実行し、可変数の注入可能な引数でコンストラクターを呼び出します。ただし、ファクトリパターンを直接使用するだけの場合は、この手順を省略できるため、ごくわずかに効率が向上します。コード。
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)
(ex $http()
)。コンストラクタを参照しているため、サービスではそれは不可能ですMyService(someArgument)
。