Git Product home page Git Product logo

Comments (8)

johnpapa avatar johnpapa commented on August 27, 2024

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.

TomSeldonBoxUK avatar TomSeldonBoxUK commented on August 27, 2024

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.

johnpapa avatar johnpapa commented on August 27, 2024

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.

johnpapa avatar johnpapa commented on August 27, 2024

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.

guillaumededrie avatar guillaumededrie commented on August 27, 2024

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.

patrick-fls avatar patrick-fls commented on August 27, 2024

@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.

guillaumededrie avatar guillaumededrie commented on August 27, 2024

Thx @patrick-fls I'll take a look! ;-)

from angular-styleguide.

johnpapa avatar johnpapa commented on August 27, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.