JavaScript Constructor Functions vs Factory Functions

Uncategorized 31 31 Comments

My previous blog post, Stop Using Constructor Functions in JavaScript has been a bit controversial, so I decided to break down the benefits vs drawbacks (or pros and cons if you prefer). Since everybody is already familiar with constructors, we’ll start there.

If you need more information and examples about factory functions, click the link above. There are also a lot more examples of factory function use in the source code from my talk, Fluent JavaScript Part One: Prototypal OO. I hope this sheds more light on the subject.

What is a Constructor?

Before we go any further, it’ll probably help to review the basics of the constructor function.

They’re pretty simple:

The call signature looks something like this:

myFoo = new Foo();

The capital letter doesn’t have any meaning to JavaScript. It’s just there to alert you that you’re calling a constructor, so you don’t forget new and break something. The special keyword, new is what matters. It sets the context of this to mean the newly created object (an instance of Foo()).

That is what this is all about. (See what I did there?)

Other than that, the constructor is just like any other function. Almost. If you return something falsy you’ll get back a new, empty instance of Foo() instead of the value you returned. However, if you return any object, including a function or array, you’ll get back whatever you returned. (Hat tip: Chris Hernandez)

The point is, you can return any arbitrary object you want, just like you can with a factory function. Try it out:

Notice how it returns the object literal instead of this? Cool, huh? A constructor is just a factory function with this glued to the new object for your “convenience”. In other words, it’s a less flexible subset of a factory function.

The problem is, it’s not really convenient. Read on!

Benefits of using constructors

  • Most books teach you to use constructors and new

  • this refers to the new object

  • Some people like the way var myFoo = new Foo(); reads.

Drawbacks

  • Details of instantiation get leaked into the calling API (via the new requirement), so all callers are tightly coupled to the constructor implementation. If you ever need the additional flexibility of the factory, you’ll have to refactor all callers (admittedly the exceptional case, rather than the rule).

  • Forgetting new is such a common bug, you should strongly consider adding a boilerplate check to ensure that the constructor is called correctly ( if (!(this instanceof Foo)) { return new Foo() } ).

  • If you do the instanceof check, it leaves ambiguity as to whether or not new is required. In my opinion, it shouldn’t be. You’ve effectively short circuited the new requirement, which means you could erase drawback #1. But then you’ve just got a factory function in all but name, with additional boilerplate, a capital letter, and less flexible this context.

What is a factory?

Simple – just a regular function that returns a new object. It behaves just like any other function would:

For more examples, check out the Prototypal OO source code mentioned already.

Benefits of using factories

  • Less code – no boilerplate required.

  • You can return any arbitrary object, and use any arbitrary prototype – giving you more flexibility to create various types of objects which implement the same API. For example, a media player that can create instances of both HTML5 and flash players, or an event library which can emit DOM events or web socket events.

  • You’d never have a need to convert from a factory to a constructor, so refactoring will never be an issue.

  • No ambiguity about using new. Don’t. (It will make this behave badly, see next point).

  • this behaves as it normally would – so you can use it to access the parent object (for example, inside player.create(), this refers to player, just like any other method invocation would. call and apply also reassign this, as expected. If you store prototypes on the parent object, that can be a great way to dynamically swap out functionality, and enable very flexible polymorphism for your object instantiation.

  • No ambiguity about whether or not to capitalize. Don’t. Lint tools will complain, and then you’ll be tempted to try to use new, and then you’ll undo the benefit described above.

  • Some people like the way var myFoo = foo(); or var myFoo = foo.create(); reads.

Drawbacks

  • new doesn’t behave as expected (see above). Solution: don’t use it.

  • this doesn’t refer to the new object (instead, if the constructor is invoked with dot notation or square bracket notation, e.g. foo.bar() – this refers to foo – just like every other JavaScript method — see benefits).

Conclusion

Stop Using Constructor Functions in JavaScript


  1. Sylvain Pollet-Villard - February 16, 2013

    I think you omit major drawbacks of using factory functions: this makes many native Object methods, attributes and operators completely useless nay misleading, such as instanceof, object.constructor, isPrototypeOf, getPrototypeOf…

    I consider more factory functions as a way to bring more flexibility to constructors when needed, ie more a wrapper than a replacement :

    this behaves as it normally would

    I guess by “normally” you mean “the way I think it should behave”. Kinda subjective. “this” has several meanings in Javascript and in my opinion, in the context of a function dedicated to build an object it should refer to this object.

    • Eric Elliott - February 17, 2013

      instanceof, Object.constructor, isPrototypeOf, getPrototypeOf"

      1) You need to be careful with all of these methods, because they don't work as expected across execution contexts -- for example, iframe boundaries. That's one of the many reasons that ducktyping (aka object feature detection) is so popular in JavaScript.

      2) I rarely find myself reaching for any of those tools anyway, probably as a consequence of using prototypal OO heavily. See Fluent JavaScript: Three Different Kinds of Prototypal OO

  2. keripix - June 14, 2013

    After reading your fluent-javascript.js file, I realise I’m one of the of those who are using “the old n busted” ways. So, after following your approach, I got stuck on how to mock for example barPrototype.open?

    I can mock easily, for example, if I just return the barPrototype.

    So, what’s your advice on this situation?

    • Eric Elliott - June 18, 2013

      I’m a little confused by your question. You can still pass the prototype around and do whatever you like with it. If you’d like to share some sample code on jsfiddle.net, that might be useful. =)

  3. Jesper Strandberg - July 13, 2013

    In your fluent-javascript.js you use anonymous functions for the membership-prototype and named functions for the availability-prototype. Am I interpreting it correct when I think the named ones are actually defined in the “outer” scope and thereby shared among the instances created? And the anonymous ones are then directly attached to each new instance, and thereby not shared?

    • Eric Elliott - July 14, 2013

      Those are unrelated concepts. I should have used named functions for all of them. The differences with named functions are 1) you can refer to the function by name from within the function (for recursion), and 2) the name will show up in your call stack while you’re debugging. You can also search for the function name with tools like tracegl ( http://trace.gl ).

  4. What about performance implications? 
    Does the modern browser JIT optimize both methods in the same way?

    • Eric Elliott - July 31, 2013

      As I’ve mentioned before: The fastest way to build an instance of an item is to return an object literal. The fastest way to attach a prototype to an object is new. Factories are slower.

      Likewise, new and constructors get optimized at property access time if you generate thousands of similar items from a constructor, and the properties mostly don’t get mutated. You can think of it like a hidden class that is eventually trusted and promoted for faster access.

      However, the performance differences aren’t very remarkable. All of the methods across the board are very fast (tens of millions of operations per second on a modern computer).

      At these micro scales, the performance difference has to be orders of magnitude different in order to warrant a second thought by an application developer (it isn’t).

      My recommendation is that you don’t even think about it unless you have a situation where you’re creating potentially millions of objects in a tight loop, and you have specifically identified object creation as a bottleneck. As for the property access thing — I wouldn’t worry about that *at all* as a software developer. The impact of the optimization at the application level is just so small that the impact of the decision will get buried under the noise of request latencies, algorithm choices, and other considerations that have a much bigger impact on your application performance. See my blog post: You’re Optimizing the Wrong Things.

  5. Great article. I’m convinced that getting away from classical inheritance clarifies and simplifies JavaScript development, so I’m super stoked the work your doing on this blog (and in conferences) to help the cause :)

    Just a side note, in your paragraph where you mention the weird JavaScript edge cases: when using new to invoke a constructor – unless you explicitly return an object from a constructor – you’ll always get a new instance, not undefined. 

  6. Sathyamoorthi - October 9, 2013

    If i follow your approach, each object will have a copy of same function. In prototype based way, all object shares the same function. So if i create, 1000 objects by your way, all i have 1000 copy of same function.

    my understanding is correct?

    • Sathyamoorthi - October 9, 2013

      I think this explains me better.
      http://www.htmlgoodies.com/beyond/javascript/object.create-the-new-way-to-create-objects-in-javascript.html

      So one should be aware about Object.create(prototype, properties) parameters. First param is prototype that is shared among all objects and second is it’s own properties.

    • Eric Elliott - October 13, 2013

      Regardless of which method you choose, you have a choice about where to store your methods: On the instance, or on a delegate prototype. The way that you assign to the prototype with a constructor function is to assign to the MyConstructor.prototype property (where MyConstructor is the name of your constructor function, obviously).

      The way you assign methods to a prototype using factories is with Object.create(myPrototype).

      In other words, the only thing that changes is how you make the assignment. The end result is the same — you have the choice of storing the methods on a delegate object, or storing the methods on each object instance.

  7. Matt Campbell - December 13, 2013

    I just came across this post and found it interesting.

    One of the drawbacks as I see it of factory functions is how do you check whether an object has inherited from another object/prototype.

    Say you have a PoliceEmployee which inherits from GovernmentEmployee which inherits from Employee which inherits from Person.

    How do you check if the PoliceEmployee is a person?

    With constructor functions you would do:

    policeEmployeeObject instanceof Person

    But how would you handle it using your factory method? I like everything about your approach but not sure how to handle this if you need to check that an object is of a certain abstract type.

    Matt

    • Eric Elliott - December 14, 2013

      Hi Matt,

      First, I generally advise against using the built-in tools for identifying if an object is an instance or descendant in JavaScript, for a couple of reasons: First, object access sometimes spans multiple execution contexts (such as window contexts and iframes), and in those cases, instanceof will fail. Second, if the prototype of the constructor gets swapped out, instanceof fails. In other words, instanceof is untrustworthy. It will lie to you eventually. There are better ways to validate that an object is a certain type. One way is tagging the object itself with a type identifier. I’m not a big fan of that method, either. Another way is ducktyping, which is what I generally prefer. A great thing about ducktyping is that you can use it to create generic functions which can act equally well on a variety of different object types — a great thing for code reuse.

      For input validation, where you need to check lots of individual properties for valid inputs, what you really want is full schema validation, which you can get with tools like JSON-schema.

      Second, those types of object hierarchies are problematic for a large number of reasons. In short, eventually every object hierarchy is wrong for new uses, and you’ll run into the gorilla / banana problem. What you want is a banana, but what you get is a gorilla holding a banana, and the entire jungle. For more on that, see my talk, “Classical Inheritance is Obsolete: How to Think in Prototypal OO”. Thanks for reading!

      • Matt Campbell - December 16, 2013

        Thanks! That talk really helped clear some things up. So basically you would check for methods and properties to see if it looks like that type of object before using the method or property. A bit like a modernizr check.

        One other question I have is in regards to initialisation. Where would you do that now? Do you create an init method which you call after the object is created by the factory function? Do you do it outside the factory function (ie create the object and then apply state to it in a wrapper function)?

        I had a look at your stampit library and it allows passing of state (properties) into the factory function, but its not powerful enough to do things like checking property type or transforming properties or doing other complex operations you may need to do like creating other objects (unless I’m totally confused).

        For example say you have a connection pool object which you want have a number of connection objects when you create it. So it needs to create a pool of other objects and store it in an array.

        In constructor land you would create those connection objects and perhaps add them to an array when the constructor is called. What is the preferred approach when using stampit or the factory function approach in general?

        • Matt Campbell - December 17, 2013

          I figured out an approach by modifying stampit to allow an init function to be passed into stampit() and if present runs this function and passes in the arguments array instead of just adding the properties to the instance object.


          var stampit = function stampit(methods, state, enclose, init) {
            var fixed = {
                methods: methods || {},
                state: state,
                enclose: extractFunctions(enclose),
                init : init
              },

              factory = function factory(properties) {
                var args = Array.prototype.slice.call(arguments),
                  state = merge({}, fixed.state),
                  instance,
                  closures = fixed.enclose

                if (typeof fixed.init === 'function') {
                    instance = mixIn(create(fixed.methods || {}),
                        state);
                } else {
                    instance = mixIn(create(fixed.methods || {}),
                        state, properties);
                }

                forEach(closures, function (fn) {
                  if (typeof fn === 'function') {
                    instance = fn.call(instance) || instance;
                  }
                });

                if (typeof fixed.init === 'function') {
                  fixed.init.apply(instance, arguments);
                }

                return instance;
              };

          Not sure if this is considered a “good” approach or not but i feel that calling an init method on the object once it has been created by the factory is really exposing the internals to the user and is a pain.

          Appreciate your thoughts.

          Matt

          • Eric Elliott - December 18, 2013

            What’s the difference between this and passing arguments into .enclose(), instead? Should there be only one init()? What happens when you compose multiple stamps that both specify init() functions? What if one init function expects a name as the first param, and another expects an array as the first param?

        • Eric Elliott - December 18, 2013

          Normally, you’d do that in the factory. Stampit lets you create functions that run at init time with the .enclose() method.

          • Matt Campbell - December 18, 2013

            Yeah its just a bit messy because the state gets polluted with parameters disguised as properties because you are forced to only accept a properties object into the factory function.

            So the properties get added to the instance object and yes you could then manipulate them inside an enclosed function but then you would need to tidy the properties/state up. It works great for simple properties you just want to pass in and set on the object, but the modifications I made allow you to also pass in paramaters which aren’t part of the state (ie they are temporary and perhaps used to create some state).

            Along the lines of the example I used before: You may have a connection pool / manager object. When you create this object it may need to be passed some connection strings to init a number of connections. This information shouldn’t be stored in the connection manager as state because its just used to create the connection objects (which are stored in the object as part of its state).

            Currently I would need to pass in the connection paramaters as properties which are set on the object, then use an enclosed function to init the connections and save each to an array on the object then I would need to remove the connection info state from the object.

            Maybe thats not a big deal, but its just doesn’t feel right because you’re adding in more code to parse and sanitise the properties than you normally would with an init method or constructor. 

            Anyway, I appreciate you taking the time to share your thoughts. I just bought your book so will read up over the next week or so.

  8. Matt Campbell - December 18, 2013

    Couldn’t reply directly above – reply button was missing.

    What’s the difference between this and passing arguments into .enclose(), instead?

    See my comments above on state properties vs function parameters.

    Should there be only one init()?

    Yes one per factory function.

    What happens when you compose multiple stamps that both specify init() functions?

    The init functions are added to fixed.inits (a new property) so that an init method which is added to the composed factory can still access the original init of each composed object.

    What if one init function expects a name as the first param, and another expects an array as the first param?

    You create an init for the composed factory and call the init methods for each composed object with the required parameters. The original init methods are stored in an array called fixed.inits.

    I’ll create a gist for the modified code and post it tomorrow for you to look at. I’m sure it’s far from perfect and you may have some ideas on improving it but this seems like the best method for initialising objects which require more than just setting properties (ie type checking and parameter manipulation to create state).

  9. Matt Campbell - December 18, 2013

    Here is the gist as promised:

    https://gist.github.com/webedia/8031010

    • Matt Campbell - January 1, 2014

      Any comments / suggestions on the gist?

    • Eric Elliott - February 13, 2014

      I really appreciate that you took the time to do this, but I’m not sure I’d like to see it in Stampit. See my comment on your gist. I think your solution is a little confusing, and adds complexity that Stampit doesn’t need.

      • Matt Campbell - June 18, 2014

        Fair enough. I suppose its more of an ideological difference. 

        I am now working on a factory library for our internal use. I may release it, but from what you have indicated it may not appeal to the wider public.

        Thanks again,

        Matt

  10. Stefan Billiet - March 19, 2014

    Hi Eric

    We talked on < about new violating Open/Closed, but I think it’s easier to continue here.

    Consider the following code:
    //DI
    function AppointmentTypeViewModel(appointmentTypeQueryService) {
      this.appointmentTypes = appointmentTypeQueryService.getAllAppointmentTypes();
    }

    //new
    function AppointmentTypeViewModel() {
      var appointmentTypeQueryService = new AppointmentTypeQueryService();
      this.appointmentTypes = appointmentTypeQueryService.getAllAppointmentTypes();
    }

    //factory
    function AppointmentTypeViewModel() {
      var appointmentTypeQueryService = AppointmentTypeQueryServiceFactory.create();
      this.appointmentTypes = appointmentTypeQueryService.getAllAppointmentTypes();
    }

    In the DI example, the viewmodel doesn’t know anything about how to construct the queryService; it receives it from a composition root. In that root, you can still make the decision to use new, or to use a factory, depending on your (evolving) needs.
    The other 2 examples violate Open/Closed, because the viewmodel is instantiating the queryservice; either it’s coupled to the signature of the constructor or to the signature of the factory.

    Or are you talking about a different way of using factories?

    I also don’t understand why people would forget to use new. It’s such a common operator in mainstream languages…

    I’m not trying to be obtuse, I just really want to understand your point of view.

    • Eric Elliott - March 21, 2014

      Imagine instead you have a game that must render at a silky smooth 60 fps. You’ve got enemies pouring out of a pirate ship, which means you have to generate pirate objects at a good clip:

      But the beastly waste monster be draggin’ the ship down trying to collect all the dead pirate bodies from the poopdeck, and the speed be droppin’ ta 14 knots (FPS).

      If ya use new, and your callers do mutinous deeds like takin’ orders from that lyin’ pirate instanceof, you can’t switch to using object pools. Oh, man, this pirate thing is harder than I thought. You should really just watch Colt McAnlis – “Slayin’ the Waste Monster: The Joys of Static Memory JavaScript”.

      Anyway, trust me, it causes all sorts of trouble if you start out making your callers use new and then suddenly switch to a factory which may or may not be powered by object pools, proxies, or other tricky beasts that confuse constructors and instanceof to no end.

      BUT, if you just start out with:

      You can easily swap out that Object.create() for an object pool, a proxy, or any type of shiny pirate booty that catches yer fancy.

      Oh yeah, and if you DO happen to have a dependency that you need to instantiate inside yer ship (factory), you can do that, too… but dependency injection is a completely separate issue… That only helps you hide instantiation details from your object creation mechanism itself — it doesn’t help you hide the instantion details of your object instantiator from the instantiator’s direct callers.

      Now walk the plank, ya filthy landlubber!

      Hmm.. sorry about that. Got a little carried away. ;)

  11. David Holmes - July 2, 2014

    Eric,
    In my experience of using ‘Functional constructors’ instead of ‘Constructor functions’, I have adopted a best practice of never using ‘this’. You just don’t need it and it opens the way to scoping issues that you generally don’t want. I’ve started using TypeScript, love it, but don’t like the way it continues the bad idea of using the ‘new’ operator. Who will write the book: TypeScript – the Good Parts?

    • Eric Elliott - July 2, 2014

      Stampit uses this in order to store and retrieve prototypes on the factory function. Doing so allows for easy code reuse and factory polymorphism. I’m not familiar with the term “functional constructors”. Douglas Crockford uses the term “functional inheritance”, which may be similar? I frequently use the term “factory functions”, which refer to functions that return arbitrary objects (possibly new objects, objects from a memory pool, proxy objects, etc…). The factory is more flexible than the constructor, which always returns this, by default. If you return something other than this from a constructor function in JavaScript, it no longer behaves like a constructor function, which might astonish users. See http://en.wikipedia.org/wiki/Principle_of_least_astonishment

Add Comment Register



Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">