When should I use factory or service in angular? [duplicate] - javascript

Please bear with me here. I know there are other answers such as:
AngularJS: Service vs provider vs factory
However I still can't figure out when you'd use service over factory.
From what I can tell factory is commonly used to create "common" functions that can be called by multiple Controllers: Creating common controller functions
The Angular docs seem to prefer factory over service. They even refer to "service" when they use factory which is even more confusing! http://docs.angularjs.org/guide/dev_guide.services.creating_services
So when would one use service?
Is there something that is only possible or much easier done with service?
Is there anything different that goes on behind the scenes? Performance/memory differences?
Here's an example. Other than the method of declaration, they seem identical and I can't figure out why I'd do one vs the other. http://jsfiddle.net/uEpkE/
Update: From Thomas' answer it seems to imply that service is for simpler logic and factory for more complex logic with private methods, so I updated the fiddle code below and it seems that both are able to support private functions?
myApp.factory('fooFactory', function() {
var fooVar;
var addHi = function(foo){ fooVar = 'Hi '+foo; }
return {
setFoobar: function(foo){
addHi(foo);
},
getFoobar:function(){
return fooVar;
}
};
});
myApp.service('fooService', function() {
var fooVar;
var addHi = function(foo){ fooVar = 'Hi '+foo;}
this.setFoobar = function(foo){
addHi(foo);
}
this.getFoobar = function(){
return fooVar;
}
});
function MyCtrl($scope, fooService, fooFactory) {
fooFactory.setFoobar("fooFactory");
fooService.setFoobar("fooService");
//foobars = "Hi fooFactory, Hi fooService"
$scope.foobars = [
fooFactory.getFoobar(),
fooService.getFoobar()
];
}

Explanation
You got different things here:
First:
If you use a service you will get the instance of a function ("this"
keyword).
If you use a factory you will get the value that is returned by
invoking the function reference (the return statement in factory).
ref: angular.service vs angular.factory
Second:
Keep in mind all providers in AngularJS (value, constant, services, factories) are singletons!
Third:
Using one or the other (service or factory) is about code style.
But, the common way in AngularJS is to use factory.
Why ?
Because "The factory method is the most common way of getting objects into AngularJS dependency injection system. It is very flexible and can contain sophisticated creation logic. Since factories are regular functions, we can also take advantage of a new lexical scope to simulate "private" variables. This is very useful as we can hide implementation details of a given service."
(ref: http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821).
Usage
Service : Could be useful for sharing utility functions that are useful to invoke by simply appending () to the injected function reference. Could also be run with injectedArg.call(this) or similar.
Factory : Could be useful for returning a ‘class’ function that can then be new`ed to create instances.
So, use a factory when you have complex logic in your service and you don't want expose this complexity.
In other cases if you want to return an instance of a service just use service.
But you'll see with time that you'll use factory in 80% of cases I think.
For more details: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/
UPDATE :
Excellent post here :
http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html
"If you want your function to be called like a normal function, use
factory. If you want your function to be instantiated with the new
operator, use service. If you don't know the difference, use factory."
UPDATE :
AngularJS team does his work and give an explanation:
http://docs.angularjs.org/guide/providers
And from this page :
"Factory and Service are the most commonly used recipes. The only difference between them is that Service recipe works better for objects of custom type, while Factory can produce JavaScript primitives and functions."

allernhwkim originally posted an answer on this question linking to his blog, however a moderator deleted it. It's the only post I've found which doesn't just tell you how to do the same thing with service, provider and factory, but also tells you what you can do with a provider that you can't with a factory, and with a factory that you can't with a service.
Directly from his blog:
app.service('CarService', function() {
this.dealer="Bad";
this.numCylinder = 4;
});
app.factory('CarFactory', function() {
return function(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
};
});
app.provider('CarProvider', function() {
this.dealerName = 'Bad';
this.$get = function() {
return function(numCylinder) {
this.numCylinder = numCylinder;
this.dealer = this.dealerName;
}
};
this.setDealerName = function(str) {
this.dealerName = str;
}
});
This shows how the CarService will always a produce a car with 4 cylinders, you can't change it for individual cars. Whereas CarFactory returns a function so you can do new CarFactory in your controller, passing in a number of cylinders specific to that car. You can't do new CarService because CarService is an object not a function.
The reason factories don't work like this:
app.factory('CarFactory', function(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
});
And automatically return a function for you to instantiate, is because then you can't do this (add things to the prototype/etc):
app.factory('CarFactory', function() {
function Car(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
};
Car.prototype.breakCylinder = function() {
this.numCylinder -= 1;
};
return Car;
});
See how it is literally a factory producing a car.
The conclusion from his blog is pretty good:
In conclusion,
---------------------------------------------------
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------
| Factory | Yes | Yes | No |
---------------------------------------------------
| Service | Yes | No | No |
---------------------------------------------------
| Provider| Yes | Yes | Yes |
---------------------------------------------------
Use Service when you need just a simple object such as a Hash, for
example {foo;1, bar:2} It’s easy to code, but you cannot instantiate
it.
Use Factory when you need to instantiate an object, i.e new
Customer(), new Comment(), etc.
Use Provider when you need to configure it. i.e. test url, QA url,
production url.
If you find you're just returning an object in factory you should probably use service.
Don't do this:
app.factory('CarFactory', function() {
return {
numCylinder: 4
};
});
Use service instead:
app.service('CarService', function() {
this.numCylinder = 4;
});

The concept for all these providers is much simpler than it initially appears. If you dissect a provider you and pull out the different parts it becomes very clear.
To put it simply each one of these providers is a specialized version of the other, in this order: provider > factory > value / constant / service.
So long the provider does what you can you can use the provider further down the chain which would result in writing less code. If it doesn't accomplish what you want you can go up the chain and you'll just have to write more code.
This image illustrates what I mean, in this image you will see the code for a provider, with the portions highlighted showing you which portions of the provider could be used to create a factory, value, etc instead.
(source: simplygoodcode.com)
For more details and examples from the blog post where I got the image from go to: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

Both the factory and the service result in singleton objects which are able to be configured by providers and injected into controllers and run blocks. From the point of view of the injectee, there is absolutely no difference whether the object came from a factory or a service.
So, when to use a factory, and when to use a service? It boils down to your coding preference, and nothing else. If you like the modular JS pattern then go for the factory. If you like the constructor function ("class") style then go for the service. Note that both styles support private members.
The advantage of the service might be that it's more intuitive from the OOP point of view: create a "class", and, in conjunction with a provider, reuse the same code across modules, and vary the behavior of the instantiated objects simply by supplying different parameters to the constructor in a config block.

There is nothing a Factory cannot do or does better in comparison with a Service. And vice verse. Factory just seems to be more popular. The reason for that is its convenience in handling private/public members. Service would be more clumsy in this regard.
When coding a Service you tend to make your object members public via “this” keyword and may suddenly find out that those public members are not visible to private methods (ie inner functions).
var Service = function(){
//public
this.age = 13;
//private
function getAge(){
return this.age; //private does not see public
}
console.log("age: " + getAge());
};
var s = new Service(); //prints 'age: undefined'
Angular uses the “new” keyword to create a service for you, so the instance Angular passes to the controller will have the same drawback.
Of course you may overcome the problem by using this/that:
var Service = function(){
var that = this;
//public
this.age = 13;
//private
function getAge(){
return that.age;
}
console.log("age: " + getAge());
};
var s = new Service();// prints 'age: 13'
But with a large Service constant this\that-ing would make the code poorly readable.
Moreover, the Service prototypes will not see private members – only public will be available to them:
var Service = function(){
var name = "George";
};
Service.prototype.getName = function(){
return this.name; //will not see a private member
};
var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'
Summing it up, using Factory is more convenient. As Factory does not have these drawbacks. I would recommend using it by default.

Even when they say that all services and factories are singleton, I don't agree 100 percent with that. I would say that factories are not singletons and this is the point of my answer. I would really think about the name that defines every component(Service/Factory), I mean:
A factory because is not a singleton, you can create as many as you want when you inject, so it works like a factory of objects. You can create a factory of an entity of your domain and work more comfortably with this objects which could be like an object of your model. When you retrieve several objects you can map them in this objects and it can act kind of another layer between the DDBB and the AngularJs model.You can add methods to the objects so you oriented to objects a little bit more your AngularJs App.
Meanwhile a service is a singleton, so we can only create 1 of a kind, maybe not create but we have only 1 instance when we inject in a controller, so a service provides more like a common service(rest calls,functionality.. ) to the controllers.
Conceptually you can think like services provide a service, factories can create multiple instances(objects) of a class

Services
Syntax: module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will be provided the actual function reference passed to module.service.
Usage: Could be useful for sharing utility functions that are useful to invoke by simply appending () to the injected function reference. Could also be run with injectedArg.call( this ) or similar.
Factories
Syntax: module.factory( 'factoryName', function );
Result: When declaring factoryName as an injectable argument you will be provided the value that is returned by invoking the function reference passed to module.factory.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances.
Providers
Syntax: module.provider( 'providerName', function );
Result: When declaring providerName as an injectable argument you will be provided the value that is returned by invoking the $get method of the function reference passed to module.provider.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances but that requires some sort of configuration before being injected. Perhaps useful for classes that are reusable across projects? Still kind of hazy on this one.

Can use both the way you want : whether create object or just to access functions from both
You can create new object from service
app.service('carservice', function() {
this.model = function(){
this.name = Math.random(22222);
this.price = 1000;
this.colour = 'green';
this.manufacturer = 'bmw';
}
});
.controller('carcontroller', function ($scope,carservice) {
$scope = new carservice.model();
})
Note :
service by default returns object and not constructor function .
So that's why constructor function is set to this.model property.
Due to this service will return object,but but but inside that object will be constructor function which will be use to create new object;
You can create new object from factory
app.factory('carfactory', function() {
var model = function(){
this.name = Math.random(22222);
this.price = 1000;
this.colour = 'green';
this.manufacturer = 'bmw';
}
return model;
});
.controller('carcontroller', function ($scope,carfactory) {
$scope = new carfactory();
})
Note :
factory by default returns constructor function and not object .
So that's why new object can be created with constructor function.
Create service for just accessing simple functions
app.service('carservice', function () {
this.createCar = function () {
console.log('createCar');
};
this.deleteCar = function () {
console.log('deleteCar');
};
});
.controller('MyService', function ($scope,carservice) {
carservice.createCar()
})
Create factory for just accessing simple functions
app.factory('carfactory', function () {
var obj = {}
obj.createCar = function () {
console.log('createCar');
};
obj.deleteCar = function () {
console.log('deleteCar');
};
});
.controller('MyService', function ($scope,carfactory) {
carfactory.createCar()
})
Conclusion :
you can use both the way you want whether to create new object or
just to access simple functions
There won't be any performance hit , using one over the other
Both are singleton objects and only one instance is created per app.
Being only one instance every where their reference is passed.
In angular documentation factory is called service and also service is called service.

Factory and Service are the most commonly used method. The only difference between them is that the Service method works better for objects that need inheritance hierarchy, while the Factory can produce JavaScript primitives and functions.
The Provider function is the core method and all the other ones are just syntactic sugar on it. You need it only if you are building a reusable piece of code that needs global configuration.
There are five methods to create services: Value, Factory, Service, Provider and Constant. You can learn more about this here angular service, this article explain all this methods with practical demo examples.
.

Related

Stuck converting ngResource angular service to Vanilla JS

We are migrating our site from old angularjs to using Vuejs.
Step one is to modify our services used throughout the site which all rely heavily on ngResource and convert them into vanilla js code that can be called by Vue.
The challenge is that in addition to making API calls using ngResource they also extending the returning object via prototype.
While using a the module pattern in regular javascript I can mimick the API behaviour of the ngResource service. But I am not clear how to set this up so that it can also support the prototype extensions that are being applied to the returning object (whether a single object or an array).
For example one of our current services might look like this
"use strict";
angular.module("myApp")
.factory("PortfolioService",
[
"$resource", "$rootScope", "$http",
function($resource,
$rootScope,
$http) {
var Portfolio = $resource("services/portfolios/:Uid",
{
'_': function() { return Date.now() }
}, {
'query': {
method: "GET",
url: "services/portfolios/",
transformResponse: $http.defaults.transformResponse.concat([
function (data) { return data.Data; }
])
}
});
Portfolio.prototype.getPicUrl= function() {
return this.ImgBasePath + this.ImgUrl;
};
return Portfolio;
}
]);
Note: that it mames a service call called query but also extends the returning object with a new function called getPicUrl.
I have created a JS equivalent that looks like this
const vPortfolioService = (() => {
var baseapipath = "http://localhost:8080/services/";
var Portfolio = {
query: function() {
return axios.get(baseapipath + "portfolios/");
}
};
Portfolio.prototype.getPicUrl= function () {
return this.ImgBasePath + this.ImgUrl;
}
return Portfolio;
})();
The service part works fine but I dont know how to do what ngResource seems to do which is to return a resource from the API which includes the prototype extensions.
Any advice would be appreciated.
Thanks
As I mentioned in my replies to #Igor Moraru, depending on how much of your code base you're replacing, and how much of that existing code base made use of the full capabilities of ngResource, this is not a trivial thing to do. But just focusing on the specific example in your question, you need to understand some vanilla JS a bit more first.
Why does the Portfolio object have a prototype property when it's returned from $resource(), but not when it's created via your object literal? Easy: The object returned by $resource() is a function, which in turn also means it's a class, and those have a prototype property automatically.
In JavaScript, regular functions and classes are the same thing. The only difference is intent. In this case, the function returned by $resource() is intended to be used as a class, and it's easy to replicate certain aspects of that class such as the static query method and the non-static (i.e., on the prototype) getPicUrl method:
const vPortfolioService = (() => {
var baseapipath = "http://localhost:8080/services/";
class Portfolio {
constructor(params) {
Object.assign(this, params);
}
static query() {
return axios.get(baseapipath + "portfolios/").then(res => {
// this convert the objects into an array of Portfolio instances
// you probably want to check if the response is valid before doing this...
return res.data.map(e => new this(e));
});
}
getPicUrl() {
return this.ImgBasePath + this.ImgUrl;
}
}
return Portfolio;
})();
But the problem is, this probably isn't enough. If you're migrating/refactoring an entire application, then you have to be certain of every instance in which your application uses ngResource, and based on your question, I'm fairly certain you've used it more than this class would allow.
For example, every class created by $resource also has static methods such as get, post, etc., as well as corresponding instance methods such as $get, $post, and so on. In addition, the constructor I've provided for the class is just a very lazy stop-gap to allow you to create an instance with arbitrary properties, such as the properties referenced by the getPicUrl method.
So I think you have three options:
Continue playing with the above class to fit something closer to what you need, and then edit every place in your application where your code relies on the Portfolio Service so that it now reflects this new, more limited class. This is probably your best option, especially if your application isn't that big and you don't have to worry about someone else's code not working
Analyze the source code for ngResource, rip it out, and modify it so it doesn't need AngularJS to work. Perhaps someone has already done this and made it available as a library? Kind of a long shot I'd guess, but it may work.
Keep AngularJS in your application, alongside Vue, but only use it to grab the essentials like $http and $resource. An example implementation is below, but this is probably the worst option. There's additional overhead by bootstrapping pieces of angular, and tbh it probably needs to bootstrap other pieces I haven't thought of... but it's neat I guess lol:
const vPortfolioService = (() => {
var inj = angular.injector(["ng", "ngResource"]);
var $http = inj.get("$http"), $resource = inj.get("$resource");
var Portfolio = $resource("services/portfolios/:Uid",
{
'_': function () { return Date.now() }
}, {
'query': {
method: "GET",
url: "services/portfolios/",
transformResponse: $http.defaults.transformResponse.concat([
function (data) { return data.Data; }
])
}
});
Portfolio.prototype.getPicUrl = function () {
return this.ImgBasePath + this.ImgUrl;
};
return Portfolio;
})();
Object instances does not exposes prototype property. Instead you can access it by using:
object.__proto__ // not recommended, or better
Object.getPrototypeOf(object)
Object.getPrototypeOf() return object's prototype object, which you can use to assign new properties.
Object.getPrototypeOf(Portfolio).getPicUrl= function () {
return this.ImgBasePath + this.ImgUrl;
}
Note: You still can, though, access the prototype of Function() by doing Function.prototype.
UPDATE: Your Portfolio should be a new object, created from the global javascript object, to avoid the issue that #user3781737 has mentioned.
var Portfolio = Object.create({
query: function() {
return axios.get(baseapipath + "portfolios/");
}
});

AngularJS - split controller functions in multiple files

I'm new in AngularJS and I'm doing a refactor of an AngularJS application and I noticed that there is a single controller file with a lot of functions that manipulate and set scope variables.
Following an example:
test.controller('testCtrl', function testCtrl($scope) {
$scope.init_filters = function() {
$scope.filter_1 = [];
$scope.filter_2 = [];
$scope.filter_3 = [];
$scope.filter_4 = [];
$scope.filter_5 = [];
};
$scope.showChanges = function() {
if ($scope.item_list.length > 0) {
$scope.messages = [];
for (var i = 0; i < $scope.item_list.length; i++) {
$scope.messages.push($scope.item_list[i].message);
}
$scope.another_function();
}else{
// other stuff
}
};
//other functions like these
}
So, I would like to split these functions in multiple JS files. I searched about this problem and I found that in a lot of case is used a service. But I think that this is not my case, because I need to working on directly on the controller's scope.
I mean, I don't want a separated function that get as parameters some scope variables and return the variable.
So, what is the best practices for doing something like this? is it possible?
If you want to use multiple files then split the definition to multiple files by passing the scope to another method and then define the rest of methods there.
File1
app.controller('CtrlOne', function($scope){
app.expandControllerCtrlOne($scope);
});
File2
app.expandControllerCtrlOne = function($scope)
{
}
Check this video
As you said the code you found for controller is large one so there are multiple ways in angular js that you can implemented the separation of code.
I will suggest you to go with following approach:
Use service to add those code in it which you need in other places as well and you know that this code does not require scope object..
Use factory to add some Utility kind of functions. The collection of logic which does not require scope object again...
As controller code is too large, I think View/UI of same also being as per wrote...
So for this you can go with creating directives for section in view..
Where-ever you think this peace of view section can be separate and standalone logical functionality that you can move into directive.
There are three ways to create directive with scopes:
A. Shared Scope B. Isolated Scope C: shared and Isolated scope
In this ways may you can at-least make your controller code readable and looks modular.
Let say::
module.controller('longRunController', function() {
#TYPE 1 code
// some code which fetch dat from API
// some code which save variable and objects which can used in another controller or directives
// some code which need to passed to other controller even after route changes
#TYPE 2
// some code which is only related this controller but has some bussiness logic
// some code which is a kind of utility functino
#TYPE 3
// all $scope related variable $watch, $scope and related variables
// some code of perticular section of which VIEW which handle by this controller
});
Consider in above patter your controller code has:
So type 1 code can be moved to Service
type 2 code can be moved to factory
type 3 code can be move to directives
you can pass $scope as a parameter to the external function.
And because you just use the objectreference, all changes you made in your external functions are made on the $scope object from your controller.
test.controller('testCtrl', function testCtrl($scope)
{
showChanges($scope);
});
...
function showChanges(scope)
{
scope.param1 = "Hello World";
}

Is it possible to use a constructor function as a type of an argument of another function in TypeScript?

A few days ago I've found a TypeScript language. According to video reviews it looks pretty promising for me as it brings to JavaScript an appropriate code completion, implicit code documentation and, probably, makes it more type safety.
I'm trying to rewrite a simple AngularJS application in TypeScript. I'd like to specify types of parameters, which are injected to controllers. Let's assume the following JS code:
// service.js
angular.module('app').service('MyService', MyService);
function MyService() {
this.test = function test() { console.log('test'); };
}
// controller.js
angular.module('app').controller('MyController', MyController);
function MyController($scope, MyService) {
$scope.test = function test() { MyService.test(); };
}
I'm trying to achieve something like this:
// controller.ts
angular.module('app').controller('MyController', MyController);
function MyController($scope, MyService:MyService) {
// ...
}
So it'd be easier to write code of the controller with code completion for MyService parameter. However, this code makes a compiler to emit error TS2304: Cannot find name 'MyService'.
I've tried a couple to things and found at least 2 possible solutions. However, non of them seems to be ideal.
1) Creation of an additional interface, which declares all methods of the service. But this approach requires a lot of additional typing (actually, we define the same set of methods with full signature twice and also have to update several things in case of changes). This way is totally okay when the interface is implemented multiple times, but looks redundant for a single AngularJS service.
2) Constructor function can be replaced with a class. This way it is possible to use a name of the class as a type of the parameter. However, this also leads to a couple of problems:
typescript compiler transforms class definitions into closures which are assigned to variables declared with var keyword (at least, dealing with ES5). This requires the AngularJS service declaration to be placed after the class definition at the very bottom of a file. It increases a possibility to forget to do it.
angular.module('app').service('MyService', MyService);
class MyService {
test() { console.log('test'); }
}
// becomes
angular.module('app').service('MyService', MyService);
var MyService = (function () {
function MyService() {
}
MyService.prototype.test = function () { console.log('test'); };
return MyService;
}());
going this way, we have to inject dependencies to a constructor function of the service. As a result, it is necessary to specify an excess this. string each time a dependency is used.
So, are there any other ways to pass a constructor function as a type of a parameter of another function? Thanks.
P.S.: I don't know whether it's necessary or not, but I'm using Sublime Text 3 with an official TypeScipt plugin and gulp-typescript for compilation.
Yes, you can do this. See working CodePen
class MyController
{
static $inject = ['MyService','$scope'];
constructor(private myService:MyService, private $scope:any){
this.$scope.test = this.myService.test;
}
}
class MyService{
test(){
console.log('test');
}
}

Is it possible to spy on or mock the value of a "behind-the-scenes" variable?

Let's say I have code that modifies a variable which is not exposed to the user like this:
var model;
module.exports = {
doSomething: function() {
...
//at some point in the code, modify model
if(/* something happened */) {
model = '123';
},
doSomethingElse: function() {
//use model in some way
}
}
};
If I later want to write a unit test to make sure that model was updated, but I do not have a getter for it, how can I test this? Is this possible to do with Karma/Jasmine/Sinon.js?
It is impossible to check the model value directly because it's hidden in a closure.
You can still write tests for it though: Your "model" will make doSomethingElse behave differently. You can verify that it matches your expectations after calling doSomething. This way, you are also free refactor the internals of your module without changing the test cases.
In general, testing private methods or properties is an antipattern. By making aspects of your implementation private, you're explicitly creating the freedom to change how those implementation details work in the future without changing your public API.
Therefore, in an ideal world, you should not (and in this case, you cannot) test the model value.
That said, we don't always live in an ideal world. So, there are some workarounds that you might consider if you really, really must test private properties and methods.
First, you could look for an environment variable, and export additional properties (by attaching them to the exports).
var model;
module.exports = {
...
}
if(process.env.ENV === 'TEST') {
module.exports.model = model;
}
Second, you can use conventions instead of making things completely private. For example, a common convention is to prefix private entities with _ to signify that they are not part of the public API. This can have varied levels of effectiveness depending on the audience that will consume your API.
Third, you could create accessors for your private variables, and check for the presence of a testing environment in some way (perhaps a global variable, an environment variable, or a variable injected into your module upon instantiation) that only allows access when the test environment is detected.
Fourth, you could allow an "inspector" object to be injected into your module (this object would only be present during testing). I have used this pattern with some success.
module.exports = function(spies) {
...
spies = spies || {};
var model = spies.model;
...
}
...
// instantiate the module in the test
var spies = {};
var mock = new Module(spies);
// do a thing
expect(spies.model).to.eql("foo");
But really, you should reconsider your testing strategy and design.

Javascript 'normal' objects vs module pattern

Currently I'm developing a large scale Javascript app(single page) and I've searched around the web to find some best practices. Most projects use the module pattern so the objects doesn't pollute the global namespace. At this moment I use normal objects:
function LoginModel(){
this.model = new MyModel();
this.getModel = function(){
return this.model;
};
}
This is readable and easy to maintain(my opinion). Is it better to use the module pattern just because of the namespacing or does it has other advantages I'm not aware of(counter memory leaks, ... )? Furthermore, I've already splitted up the files to have a nice MVC pattern and destroy every object when needed(counter memory leaks). So the main question is: do I need, in my case, to use the module pattern or not?
Module pattern:
var LoginModel = (function(){
var model = MyModel;
function getModel(){
return model;
};
return {
getModel: getModel
};
});
The module pattern is better for overall code organization. It lets you have data, logic and functions that are private to that scope.
In your second example getModel() is the only way to get the model from the outside. The variable declared int he module are hidden unless explicitly exposed. This can be a very handy thing.
And there's not really any drawback, other than being a little more complex. You just get more options for organization and encapsulation.
I'd use a plain object until my model gets complex enough to need more structure and some private scoping. And when you hit that point, it's trivial to redefine it as a revealing module without breaking any of the code that uses it.
If you're only going to be using one instance per page, I don't see the need to involve the new keyword. So personally I would create a revealing module like you did in your last example, and expose an object with the "public" properties.
Though I don't see your point with the getModel() function, since MyModel is obviously accessable outside of the scope.
I would have rewritten it slightly:
var LoginModel = (function(model, window, undefined){
function init(){ } // or whatever
function doSomethingWithModel(){
console.log(model);
}
return { init: init };
})(MyModel, window);
If you're uncertain of which modules that will get a model, you can use loose augumentation and change
})(MyModel, window);
to
})(MyModel || {}, window);
If you need several instances of a module, it would look something like this:
var LoginModel = (function(model, window, undefined){
function loginModel(name){ // constructor
this.name = name; // something instance specific
}
loginModel.prototype.getName = function(){
return this.name;
};
return loginModel;
})(MyModel, window);
var lm1 = new LoginModel('foo');
var lm2 = new LoginModel('bar');
console.log(lm1.getName(), lm2.getName()); // 'foo', 'bar'
There's several concepts conflated in your question
With what you call the "normal object", the function becomes a constructor function and requires the new keyword.
The second example uses the Revealing Module Pattern inside of an IIFE. This is the most popular variant of the Module Pattern, but unfortunately deeply flawed. For an explanation of the differences see my answer here, and for its flaws, see here.
Now, your question poses a false dichotomy -- normal objects or module pattern? You don't have to make a choice -- a normal object can use the module pattern simply by putting whatever it wants to keep private inside its closure scope. For example,
function LoginModel(){
var _notifyListeners = function(){
// Do your stuff here
};
this.model = new MyModel();
this.getModel = function(){
_notifyListeners();
return this.model;
};
}
This is an example of a "normal object" using the module pattern. What you have to avoid doing is what the Revealing Module Pattern does -- putting everything into closure scope. You should only put the things you want to keep private inside the closure scope.

Categories

Resources