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
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).
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.
This code uses Object.create() to create a new instance with the shared
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.
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
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.
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.
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.