Stop Using Constructor Functions in JavaScript

JavaScript 42 42 Comments

Public constructors are problematic for a number of reasons, but chief among them for me is that they couple the calling code to the constructor implementation. In other words, it forces you to break the open/closed principle. Later on, if you need to make your object instantiation polymorphic, you’ll end up invalidating all of the code that used new directly.

You might want to create a function that acts a bit like a constructor function, only it’s capable of returning multiple types of objects which will satisfy the contract of the interface (this is a lot like the purpose of an abstract class in other OO languages).

This design sensibility is true in all OO languages (several of the GoF design patterns address this very issue), but in JavaScript, it gets even worse. If you forget to use new for a constructor, but then you go assigning things to this inside your function, this is not the object you think it is, and you can end up with all sorts of nasty bugs involving accidentally shared state and so on. I’ve seen this stump a couple of different developers just in the past month. One forgot to use new to invoke a Backbone model (with disastrous consequences), and another left new off a constructor call in Node, which caused a bizarre, hard-to-find bug that you had to look in two different files to spot.

The good news is that there is absolutely no need to use constructors in JavaScript. Just export a function that returns any object you want. You can even create flyweight objects that share public methods:

This code uses Object.create() to create a new instance with the shared prototype. For more detail on that, check out my recent talk on prototypal OO in JavaScript.

Constructors Make Polymorphism Harder

For example, say you have video player logic with multiple concrete implementations: HTML5 and flash. Using a factory (instead of a constructor), it’s pretty easy to detect the browser capabilities and return a new object with the HTML5 prototype for browsers that support it, or the flash prototype for browsers which don’t. Adding new prototypes to a factory is trivial.

Using constructors and this, you’d have to alter constructor logic to add that functionality, especially if you’ve attached all the functions one at a time directly to the constructor’s prototype property after declaring the constructor.

Why new Violates Open/Closed

If you start with a constructor and later want to replace a constructor with a factory (the open for extension part of the open/closed principle), every place that referenced the constructor needs to change, because fetching the new object is coupled with the constructor method of instantiation via the new keyword. Trying to use new with a factory could cripple some of it’s capabilities and return broken objects.

Which leads to another rule of thumb: Don’t use this to address a new object being constructed inside a factory. It works fine in constructors, but if you try to build up an object with this inside a factory, and then return an arbitrary object like with return Object.create(myPrototype); — the stuff attached to this is not exposed as you intended. However, if you don’t try to call a factory with the new keyword, this is a handy reference to the properties of the object of which the factory is a member — a handy way to access the available prototypes. Extending the available prototypes is easy; just attach them to the factory object.

Don’t Capitalize

You might be tempted to capitalize the first letter of your factory methods, because you’ve been trained to capitalize the first letter of constructors.

Don’t.

Some lint tools will complain that you’re “missing new” calling the factory. Then you use new, and suddenly you can’t access your prototypes.


  1. Object.create is not supported in the following document modes: Quirks, Internet Explorer 6 standards, Internet Explorer 7 standards, Internet Explorer 8 standards. http://msdn.microsoft.com/en-us/library/ff925952(v=vs.94).aspx

    • svlada It’s very easy to polyfill:if (!Object.create) {Object.create = function (o) {if (arguments.length > 1) {throw new Error(‘Object.create implementation only accepts the first parameter.’);}function F() {}F.prototype = o;return new F();};}

  2. Wil Moore III - November 20, 2012

    > forgot to use new

    Linting the code would mitigate this. Closure compiler would catch it as well.

    Seems to me, if one has a sane quality checking process, there is little to no reason to broadly say never or always.

    • Eric Elliott - November 29, 2012

      As I mentioned in the article, forgetting new is not my biggest reason to avoid constructors. The biggest reason is the violation of the open/closed principle.

      Unlike factories, constructors leak the “how” of object creation into the API — and they do it with syntax that is more awkward than the alternatives — so why would you ever want to use them?

  3. Armagan Amcalar - January 3, 2013

    Eric, I guess you need concrete examples to illustrate your point.

    Furthermore,

    “If you start with a constructor and later want to replace a constructor with a factory (the open for extension part of the open/closed principle)” is kind of controversial, since “replacing a constructor with a factory” is “modification”, which should be “closed”. Extension would be refactoring the constructor for an abstraction for the two implementations (Flash and HTML5 video player).

    • Eric Elliott - January 5, 2013

      I’ll be happy to add more concrete examples. I’m giving a talk on this at the O’Reilly Fluent conference in May. I’ll post updates, and possibly an excerpt from my book to illustrate in more depth.

    • Yeah, I don’t really get the argument here. I’d like to see some more explicit examples.

      The example provided shows the line var t2 = new factory.create(); as being broken after changing a constructor into a factory. But from what I can tell, it would be broken regardless of “new” usage, because you’ve renamed some function to “factory.create()”.

      Convention carries a lot of weight; if you follow convention, other developers can look at your code and know exactly what’s going on. I need to be absolutely convinced that something is irreparably broken with the convention before I change how I do things, otherwise I’m just making my code harder to maintain. So far, I’m not convinced.

  4. Cem Gur - January 3, 2013

    totally bullshit

    • Eric Elliott - January 5, 2013

      Maybe you could get more specific about your objections…

    • Let’s put it this way:

      If you’re writing a module or library that’s meant to be consumed by other code, there can be performance reasons to use the Constructor pattern internally. However, there is never a good enough reason to expose this implementation detail to outside consumers of your library.

      If I’m using your library, the only thing I need to know is that, when I call widget() I’ll get an object that conforms to widget’s specifications and interface. If calling widget() has side effects (such as polluting the global scope), then you fail as a library designer.

      To new or not to new is not a question I should ever have to ask.

  5. Hi, nice article!
    I will probably would wanted to see more about factory in action.
    In any case, have consider using Functional OOP as Douglas Crockford described in his book, JavaScript – The Good Parts ?
    Why factorys are better than Crockford OOP (it includes an easy way to use inheritance, private atributes and methods, among other beneffits, and it also doesnt use new keyword)

    Regards

    • Eric Elliott - January 5, 2013

      That’s just another name for “factory function”. He goes into more detail about how to construct other patterns using factory functions, but the basic concept is the same.

  6. Dan Shappir - January 8, 2013

    Factories are indeed a good design pattern. A problem with factories in various programming languages is the inability to inherit implementation from classes owned by factories, because the class definitions are hidden inside the factories. Instead the delegate design pattern must be used, which requires more work to implement.

    In JavaScript OTOH it’s easy to inherit implementation in such a scenario: simply use an object returned from a factory as the proto parameter for Object.create. You can even use this mechanism to create new factories that enhance the operation of objects created by a different factory. For example, pass one factory as parameter to another factory function, and use an object created by the former as the prototype for the latter.

    Hope this is clear :)

    @DanShappir

    • Dan Shappir,
      Very clear, nice suggestion. Now, I need an array of objects, created with the factory returned proto parameter. All objects will be the same the same type = whatever the factory generates. Any ideas how this might be accomplished without having to call on the factory function to return the object param more than once?

      • Eric Elliott - February 11, 2013

        Dave,

        I’m not sure how frequently you’d actually come across the use case where you want an array of identical objects to come out of a factory. Usually, you’ll want to set some state on those objects that makes them unique (or else you’d really only need one object, right?)

        The more common pattern is to make the factory take parameters, and then loop through inputs and call the factory method for each of the unique inputs, yielding a new, unique object whose state is influenced by the given input.

        This weekend I took some time and cranked out a library to make the process easier. It’s called Stampit, and it makes it easy to create objects from reusable, composable behaviors.

  7. Resig has a good example of making “new” optional, seems this would discount most of your objections:

    http://ejohn.org/apps/learn/#36

  8. There are a lot of people coming from classical OO who still don’t quite get why constructors are unnecessary and antithetical to the roots and nature of the language. Nevertheless, it seems we’ll have proper classes in JavaScript when Harmony is released:

    http://wiki.ecmascript.org/doku.php?id=harmony:classes

    What’s your take on this? Good thing? Bad?

    • Eric Elliott - April 18, 2013

      First, you linked to the wrong classes. Those have been superseded by the maximally minimal classes strawman, which is now part of the most recent draft.

      You’ll want to refer to my post, Fluent JavaScript: Three Different Kinds of Prototypal OO. Read that, then come back here for the rest of this discussion.

      I think that a lot of people are going to use and like the new classes. They are much closer to classes you’ll find in other languages than anything JavaScript currently offers. I think that many will consider the debate settled, and switch to pseudo-classes instead of taking full advantage of prototypal OO, and in my opinion, that is a very sad development for JavaScript. I would bin the new classes with the rest of the “ugly parts” simply because right now, as of this writing, we have something better. We should just learn and use this better thing we have. I really wish we could have seen a better prototypal abstraction go into the new draft of the language, instead of taking a giant leap backwards into class semantics.

      If you use the new classes, you should be aware that you’re boxing yourself into a corner a little bit. For example, you can’t do those multiple inheritance examples I showed off in the Fluent JavaScript post, and the functional prototypes would require horribly brittle super() chaining, and if you use super(), you’re doing it rong. (See below).

      Here’s what an interpretted excerpt from Three.js would look like with the new maximally minimal classes (from the strawman):

      And here’s what it would look like with stampit (which you don’t have to wait for to use).

      I don’t know about you, but I find the stampit version less ambigous, and slightly easier to read. Granted, it’s missing the constructor parameters, and super call, but that’s because:

      1. I made a conscious decision with stampit to make any parameters you pass into
        a stamp get added to the public properties (object state), because 99% of the time, that’s what you want, so, if that’s what you do with geometry and materials, that’s already supported with no more code (of course, that’s not in this case.)
      2. The design that three.js is using here is not one that I would recommend (see my note about super(), below).

      Stampit can run a method that takes parameters at object init, but the options hash would become a public property on the object, and you’d want to pass an init function into the .enclose() method.

      A note about super()

      Super is a code smell. It makes your code brittle by creating strong coupling between the child and the parent. You should really add a hook in mesh to handle this see
      Martin Fowler’s blog post about super().

      If you really MUST have super, just call the method directly, instead of relying on a sugary keyword for something that should be discouraged.

      What’s wrong with class?

      Now, for the fun part: Reproduce my stampit examples with the new class construct:

      Well, at least it’s concise.

      • Just say No to inheritance and classes :

        var skinnedMesh = (function () {
            var implementation = three.mesh ;
            var state = {
              identityMatrix : three.matrix(),
              bones: [],
              boneMatrices: [],
              geometry: [],
              materials: []
            } ;
                return { /* interface */
                      update : function ( camera ) {
                          /* from here reach the implementation and/or state */
                      }
               } ;
        }());

        If one needs pain (aka classes, OOP and a such) one is free to use any of the available harm inducing products like: TypeScript, CoffeScript, Dart and a such…

  9. Classes, inheritance and polymorphism? Why would anybody use these in ES5 ?

    • Eric Elliott - June 29, 2013
      • I was not clear : Classes are obsolete. Therefore whatever one can do with them is obsolete discussion. Inheritance including. Same can be proven for keywords “new” and “this”.  Forget these three and live happy and productive JS life:

             var module = (function () {
                      var implementation = { } ;
                     
                      return { /* interface */
                      } ;
              }());

        The key abstraction, sadly forgotten by ES6 “central committee” is: INTERFACE. 
        Software is made of components. Every Component has interface. 

        Inheritance is evil. Use aggregation.

        End of rant.

        • Eric Elliott - July 3, 2013

          dbj – we’re pretty much on the same page. Except that I go into a lot more detail about the good alternatives. I think it’s also important to mention that setting a prototype in JavaScript isn’t inheritance in the sense that most people know it. It’s actually *method delegation*, and that is actually pretty great. Just don’t go subclassing things. Subclassing is evil. Aggregation / composition / delegation = good.

          • @eric we are on the same page, beside one thing: I can not allow alternatives, I need to deliver software. We have no time debugging through someones alternative ES5. Just not feasible.
            As I said above, for the persistent devotees there are class based OO alternaties to ES5. And some of them can be used straight away instead of ES5: TypeScript, Coffee Script, Dart, Lua … whatever tickles one’s OOP fancy. I simply use the good parts only … not even that …a subset of good parts that is :)

          • Eric Elliott - July 4, 2013

            I don’t know what you mean by “I can not allow alternatives”. If you’re not using classes, but you are programming, you are by definition using an alternative to class, whether that alternative is modules with object literals (as you demonstrated), aggregation, functional programming, etc… If you haven’t yet, you really should watch my talk, “Classical Inheritance is Obsolete: How to Think in Prototypal OO”: https://vimeo.com/69255635

  10. @eric clarification (in danger of privatising this thread) … what am I saying is do whatever you like (and give it any name you like) but please observe only one single and simple requirement: your code must not use two keywords: new and this … :)

    my “challenge” or proposal is that this approach simply produces  fast, reliable and clean ES5 code.

    btw: even more reduced subset of ES5 produces much more spectacular results using asm.js approach.

    Thanks ….

    • Eric Elliott - July 14, 2013

      I totally agree with you about new. However, this is useful in methods to refer to public state on the current object, other methods on said object, and to return the object itself from methods to allow for chaining. IMO, those are legit use-cases.

  11. Hi Eric,

    Great post. Just came across it after having written my own post making a similar argument from a different angle: https://tareksherif.ca/blog/2013/08/constructors-are-bad-for-javascript/

    Would love to hear your thoughts.

    • Eric Elliott - August 9, 2013

      Good points… however, in real world code, I’ve never seen instanceof or isPrototypeOf create problems in the way you described. More frequently, I’ve seen them cause problems when people attempt to use them across execution contexts (such as iframes). See my comment on your post.

      A good alternative to instanceof and isPrototypeOf in JavaScript is ducktyping. If whatever gets passed in seems to support the features you need, just use it:

      • I’ve replied to your comments in more detail on my post, but I’ll summarize here for those reading thing thread.

        I agree that the object-constructor links won’t generally cause problems in real world code, but I found it interesting that the whole class/constructor/new/instanceof mechanism is so fundamentally broken in JavaScript. And I’ll add that one real-world issue I do see with them is that they make it harder for new developers to understand how JavaScript actually works. They are misleading. It’s almost like a kind of bait and switch for Java developers.

        Duck typing, yes! I use it all the time in my Ruby development, as it’s more explicitly the standard there. It’s extremely flexible. And people essentially already use it in JavaScipt: in the idiom “Array.prototype.slice(arguments)”, are you not duck typing “arguments” an object that isn’t an array, but has the properties to act like one? It’s just a matter of applying that approach in a more general way to development.

        • Eric Elliott - August 10, 2013

          Yeah, duck typing is very common. But instead of Array.prototype.slice(arguments), you should try [].slice.call(arguments);. You forgot .call() (the other version will return an empty array). What it does is treat arguments like an array (passing it into .slice() as the value for this, even though it isn’t an array, and returns a copy that actually is an array. 

          • Ack! That’s a systematic typo for me. Perhaps, a better example would be Array.prototype.slice.call(arguments, 1) (to get all arguments except the first one), so that we’re actually using the method for something besides a simple copy. The reason this, and other Array methods, work on a non-Array object like arguments is that the methods don’t do any type checking. As long as the object bound to this has the needed properties (I think just a numeric length property and indices), the methods will work. This is a form of duck typing that’s in common use, though I don’t think it’s usually referred to as such among JavaScript developers.

          • Eric Elliott - August 13, 2013

            Methods like .slice() which use duck typing instead of type checking are known as generic methods, which just means that they’ll work on anything that supports the requirements. They work because they use duck typing internally.

  12. Hi Eric.

    Theoretically your arguments are very convincing but in the practice when you have to make a complex inheritance, the Object.create pattern is pretty much difficult and verbose.

    “Constructors Make Polymorphism Harde” can you illustrate this with some example?

    About your implementation of factory, of course throw an error because the implementation is not correct. An example with constructor instead of object.

    var factory = function(){ return {foo: 'bar'}; };
    factory.create = function () { return new factory; };
    var t1 = factory.create();
    t1.foo; // "bar"
    var t2 = factory.create();

    That is wrong?

    I really would like to get a answer here because i think not too many people can answer me:
    http://stackoverflow.com/questions/20266358/understanding-why-true-prototypal-inheritance-is-better-than-classical-pseudo-pr

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="">