Comments (8)
Prototype would be great if you create several of these objects (controllers in this case). That would make it worth it. But often we are talking 1 controller ... or maybe just a small handful. I'm not seeing the benefit for this use case. Is there another you are thinking of?
from angular-styleguide.
Well, there's a few reasons why I'd still argue this is the better approach:
Performance
Given that in that vast majority of cases it's orders of magnitude faster than just using closures, it's at worst a micro-optimisation and at best could see tangible performance gains. Particularly in the case of controllers, where it's entirely feasible to have many instances of controllers that could be destroyed, re-instantiated and just generally just "well used". The performance difference would probably be less evident on singletons (services, factories, etc), due to their one-time instantiation, but gains would still be found when accessing and using those singletons.
The actual number of providers, as you point out, will differ for each application and use case. However, even taking into account my (very trivial) example above, I'd argue that it shouldn't matter whether that controller was the main part of a micro-app or a tiny piece in a complete behemoth of an application- the method by which you define it should be the same in both. This enforces consistency as well as scalability.
Also, to address your point of the use-case of having multiple controllers: taking into account the single responsibility principle, it's completely feasible to split up a single view into sections that are managed by separate controllers (or else end up with a kind of 'god controller' that manages far too much). So I'd say aside from in the most trivial applications, you'd have multiple controllers that are responsible for constructing their respective view-models.
Language conventions
Prototypes are a core part of JS, so performance issues aside it seems like it should be the de facto method of creating objects such as this. A decision can then be made on a case-by-case basis on whether there's a reason to depart from that.
There's also the more subjective reasons such as readability, IDE code hinting and structure information, and possibly better integration with tools like JSDoc (though I haven't experimented enough with it to be to certain of that last point).
So, with the advantages in mind, a more succinct question would be...
Are there any reasons not to use prototypes instead of closures?
Disadvantages
I've been trying to think of possible disadvantages of the prototype approach, and I've been coming up quite short, but stick with me...
No more var that = this
It's mentioned in the style guide as a good practice to use the old var that = this
in order to keep a reference to the object when it may otherwise fall out of scope (e.g. event handlers).
I was going to raise a separate question for this, but there's a bit of overlap with what's being discussed here so I'll touch on it briefly.
// Closure example, as per existing style guide
var ClosureController = function(myService)
{
var vm = this;
vm.someProperty = 'foo';
vm.otherProperty = 'bar';
vm.exposedMethod = function()
{
myService.someAsyncMethod()
.then(someCallback);
};
function someCallback(data) {
// `this` may not refer to the controller here, but `vm` still does
}
};
The same in a prototyped controller would be:
var PrototypedController = function(myService)
{
this.myService_ = myService;
this.someProperty = 'foo';
this.otherProperty = 'bar';
};
PrototypedController.prototype.exposedMethod = function()
{
this.myService_.someAsyncMethod()
.then(this.someCallback_.bind(this));
};
PrototypedController.prototype.someCallback_ = function(data)
{
// `this` refers to the controller, due to correctly binding the function invocation
this.someProperty = data.someResult;
};
Harder to create private properties and methods
Looking at the two examples above, one disadvantage that should be clear is that in ClosureController
, someCallback
is effectively private to the controller, whereas in PrototypesController
, the someCallback_
method is technically still exposed to the view and we have to infer the fact that it's private from the trailing underscore.
Is that a big issue? I'd say when you start going down the road of trying to strictly enforce private values in Javascript, you're fighting a losing battle and should look at using an compile to JS alternative that offers compile time checking (e.g. Google Closure, Typescript, etc).
Or, you could keep using prototypes and use the revealing module pattern to expose only what's needed.
The above PrototypedController
could be refactored as:
var PrototypedController = function()
{
// same properties as above, omitted for brevity
return {
exposedMethod: this.exposedMethod.bind(this)
};
};
PrototypedController.prototype.exposedMethod = function()
{
// same code as above example
};
PrototypedController.prototype.someCallback_ = function(data)
{
// same code as above example
};
The difference would be that if you were to inspect the returned controller instance, you'd have:
// First PrototypeController example
{
myService_: function() { //service instance },
someProperty: 'foo',
otherProperty: 'bar',
exposedMethod: function() { // stuff },
someCallback_: function(data) { // stuff }
};
// Second PrototypeController example (revealing module)
{
someProperty: 'foo',
otherProperty: 'bar',
exposedMethod: function() { // stuff }
};
So it's still possible to achieve the same result in a clean way.
Conclusion...
Just to re-iterate the question I raised somewhere in the middle of all of that, I'd say a fairer question would be what are the reasons for not using prototypes? You're response reads as though there is an implementation penalty that isn't worth the benefits- I'm just not really seeing that penalty. Both seem about the same effort and complexity.
Is there something I'm missing?
from angular-styleguide.
There is no penalty for using it and it is perfectly acceptable to use one here. I do not believe it should be a style for this guide as it is a choice. The performance gains in most situations will be so negligible that it won't make a difference, but for those situations where it might it could be used.
I do not believe the readability is as clear and the gains large enough to use in every Controller. Should they be used in one offs? Sure. Again, it is a style guide and I encourage you to use this as such. If your team wants to use prototypes then you should most certainly do so.
Consistency amongst a team is important.
Thanks for taking the time to write this up.
from angular-styleguide.
I think there may be a point where this could be useful tip when creating a Controller, with bindable functions, for a directive that is used in ngRepeat ... to help with performance. Say for 100 instances. Would be interesting to see a jsPerf test with that and without.
from angular-styleguide.
Hi,
Thx @johnpapa, you did an amazing work!
Related to this issue, I was wondering if there is a possibility to use both closures and prototypes.
An example for data repositories and data models from the Naorye blogpost http://www.webdeveasy.com/angularjs-data-model/.
Imho, bookManager should be rewritten using closures, but Book model is fine using Prototypes…
What's your thoughts on this?
Regards,
Guillaume
from angular-styleguide.
@guillaumededrie my 2c ( for what it's worth!) I would rewrite everything in this article using $resource instead. That's exactly for what module was written for.
I don't think a Book object should know how to get the it's data, it's the job of the service. I'd have a BookService handling $resource with special / custom calls to CRUD models transformed in the controller. Your BookService with $resource should be unique enough that you don't need to prototype anything, as $resource does the heavy lifting.
See #70 where I asked a question about inheritance in general, got some good answers.
from angular-styleguide.
Thx @patrick-fls I'll take a look! ;-)
from angular-styleguide.
@guillaumededrie I would work on a book service that handles manipulating books. The controllers can ask the book service to perform actions such as getBooks or saveBooks. I prefer to separate the need for a model from a service. In other words, the data model knows not where it gets its data from. I don;t see a need for prototype or inheritence here.
from angular-styleguide.
Related Issues (20)
- Y022 - Naming Conventions For Functions Inside IIFE HOT 1
- JS Hint configuration code is out of date.
- Best way for long controller $inject HOT 7
- Can you give simple Hello World Program? HOT 2
- dataService calls when inside page controllers vs component/directive controllers. HOT 2
- Best way for required directive attribute HOT 2
- NetBeans templates, redux? HOT 1
- Best Practices for `templateUrl` and `ngInclude` URLs HOT 3
- Arrays under scope.vm of directive undefined HOT 7
- Proposal: change from "do" to "consider" adding 'Service' suffix to Service (02-04) classes because it doesn't improve clarity or add value HOT 7
- Where is the best location to place HttpInterceptors?
- Why styleguide suggest use class instead of interface? HOT 3
- A1 - How to pass object received with $routeProvider to other route HOT 1
- Style 03-05 missing! HOT 1
- Angular 5 style guide? HOT 1
- Confusing Information on SharedModule and CoreModule HOT 3
- Should "public" always be omitted in TypeScript? HOT 1
- Private variable - leading underscore HOT 7
- Jasmine Test case failing HOT 1
- AngularJS-UnitTesting | Weather App | Karma
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from angular-styleguide.