Stop Using Constructor Functions in JavaScript

JavaScript 25 25 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.




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 lang="" line="" escaped="" cssfile="" class="" title="" data-url=""> <span class="" title="" data-url="">