164

Can someone clarify the difference between a constructor function and a factory function in Javascript.

When to use one instead of the other?

Sinan
  • 5,424
  • 9
  • 34
  • 65

8 Answers8

165

The basic difference is that a constructor function is used with the new keyword (which causes JavaScript to automatically create a new object, set this within the function to that object, and return the object):

var objFromConstructor = new ConstructorFunction();

A factory function is called like a "regular" function:

var objFromFactory = factoryFunction();

But for it to be considered a "factory" it would need to return a new instance of some object: you wouldn't call it a "factory" function if it just returned a boolean or something. This does not happen automatically like with new, but it does allow more flexibility for some cases.

In a really simple example the functions referenced above might look something like this:

function ConstructorFunction() {
   this.someProp1 = "1";
   this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };

function factoryFunction() {
   var obj = {
      someProp1 : "1",
      someProp2 : "2",
      someMethod: function() { /* whatever */ }
   };
   // other code to manipulate obj in some way here
   return obj;
}

Of course you can make factory functions much more complicated than that simple example.

One advantage to factory functions is when the object to be returned could be of several different types depending on some parameter.

Eric Elliott
  • 4,387
  • 1
  • 23
  • 33
nnnnnn
  • 138,378
  • 23
  • 180
  • 229
  • 17
    "(EDIT: and this can be a problem because without new the function will still run but not as expected)." This is only a problem if you try to call a factory function with "new" or you try to use the "this" keyword to assign to the instance. Otherwise, you simply create a new, arbitrary object, and return it. No problems, just a different, more flexible way to do things, with less boilerplate, and without leaking instantiation details into the API. – Eric Elliott Jan 05 '13 at 14:10
  • Note that returning an object from factory doesn't really make much sens. Returning a function from the factory would make sens as parameters could be pre-calculated (e.g. RegExp could be compiled) and passed into the function that is returned... – Nux Aug 16 '13 at 03:35
  • @Nux - Returning an object from a factory function makes perfect sense and is a common thing to do. (Obviously you'd normally have something more complicated than a couple of hard-coded properties as in my example.) – nnnnnn Aug 20 '13 at 21:58
  • You can pass parameters to both and both will get a context isolation, so I don't see any actual gain. That's why I wrote that returning a function could bet better - at least performance wise. – Nux Aug 20 '13 at 22:23
  • @Nux - The point is that if what you need is a way to create similar objects you normally use either a constructor function or a factory. If you're using the objects to store data (e.g., an "employee" object) you don't need to return a function, an object will do fine. (Obviously you _can_ return a function for cases where it makes sense, but it doesn't make sense everywhere.) – nnnnnn Aug 20 '13 at 23:18
  • The example that you've used for the factory function is rather non-standard and thus confusing. You'd still use `new` inside a factory function, which allows you to share methods between instances of the same class using `ConstructorFunction.prototype`. With your way of creating objects inside the factory function, one would not be able to share methods between instances of a class. – Bharat Khatri Mar 05 '14 at 15:15
  • @BharatKhatri - I disagree. You certainly _can_ use `new` inside a constructor function, and I'm not in any way saying that is a bad thing to do, but you don't have to. The pattern I've shown isn't something I've used a lot, but I it is appropriate for some circumstances and I've certainly seen it used effectively in other people's code. And as I said in the answer, it's a really _simple_ example. – nnnnnn Mar 05 '14 at 21:22
  • 7
    I wanted to point out that the examples for both the cases (constructor function vs factory function) should be consistent. The example for the factory function doesn't include `someMethod` for the objects returned by the factory, and that's where it gets a bit foggy. Inside the factory function, if one just does `var obj = { ... , someMethod: function() {}, ... }`, that would lead to each object returned hold a different copy of `someMethod` which is something that we might not want. That is where using `new` and `prototype` inside the factory function would help. – Bharat Khatri Mar 05 '14 at 22:16
  • @BharatKhatri You don't have to use `new` to get that. You could also use `Object.create()` (my preferred method). If you want support for old browsers, there's a four line polyfill that will give you what you need. – Eric Elliott Mar 15 '14 at 03:13
  • @BharatKhatri - The examples weren't intended to be consistent because I disagree that they should be: if the factory function had exactly the same result as a constructor with `new` then you wouldn't need both. And I didn't want the answer to be too long with lots of examples. The last sentence of the answer does indicate that factory functions can return specific types (whether using `new` or `Object.create()`), not just generic objects. If you really feel that I've fallen short here, feel free to downvote and/or post a more complete answer of your own. – nnnnnn Mar 15 '14 at 08:11
  • 3
    As you already mentioned that some people try to use factory functions just because they don't intend to leave bugs where people forget to use `new` with the constructor function; I thought it's where one might need to see a __how to replace constructors with factory functions__ example and that's where I thought the consistency in the examples was required. Anyway, the answer is informative enough. This was just a point I wanted to raise, not that I'm pulling down on the quality of the answer in any way. – Bharat Khatri Mar 15 '14 at 10:14
  • 4
    For me the greatest advantage of Factory functions is that you get better **encapsulation** and **data hiding** which may be useful in some applications. If there is no problem in making every instance property and methods public and easily modifiable by users then I guess the Constructor function is more appropriate unless you dislike the "new" keyword like some people do. – devius Sep 29 '14 at 11:36
  • @nnnnnn Sorry, I commented on the wrong answer. It was meant for eric-elliot who also wrote the article [Stop Using Constructor Functions in Javascript](http://ericleads.com/2012/09/stop-using-constructor-functions-in-javascript/) – Wayne Bloss Nov 07 '14 at 20:24
  • When using a constructor with a prototype method, that method will exist in only one instance. You can create many objects with the constructor, but they will all call that prototype method. -- Is there an equivalent solution for the factory method? Can prototype methods be leveraged in the factory method, where the function returns a literal object? – Federico Jun 17 '15 at 18:05
  • 1
    @Federico - factory methods don't have to return just a plain object. They can use `new` internally, or use `Object.create()` to create an object with a specific prototype. – nnnnnn Jun 18 '15 at 00:55
  • If one were to use a Factory Function (FF) like this (probably worth viewing in a text editor): `function FF(constructorArg) { var _privateName = constructorArg; var publicMessage = "Hello StackOverflow"; function publicMethodGetName() { return _privateName; } return { publicMethodGetName: publicMethodGetName, publicMessage: publicMessage }; }` and was sure that they would NEVER use the 'this' keyword inside the FF, would it then be acceptable to do var ff = new FF()? That way you get the readability of using 'new' and don't need to worry about the problems with the 'this' keyword. – user5508297 Aug 21 '16 at 03:16
  • Why would you want to use `new` in that situation rather than just `var ff = FF()`? In my opinion it is *less* readable if you are deliberately ignoring the standard operation of `new`. – nnnnnn Aug 21 '16 at 03:23
  • @nnnnnn I take your point but I'm not deliberately ignoring the standard operation of `new` - I'm simply avoiding it by using a style where it doesn't hurt (e.g. coding `function ffMethod() { return 1; }` rather than `this.ffMethod() { return 1; }` If I make this clear in comment to people reading my code then I think it would only offer benefits? Let me know what you think. – user5508297 Aug 21 '16 at 18:21
123

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() } ). EDIT: Since ES6 (ES2015) you can't forget new with a class constructor, or the constructor will throw an error.

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

Constructors break the Open / Closed Principle

But my main concern is that it violates the open/closed principle. You start out exporting a constructor, users start using the constructor, then down the road you realize you need the flexibility of a factory, instead (for instance, to switch the implementation to use object pools, or to instantiate across execution contexts, or to have more inheritance flexibility using prototypal OO).

You're stuck, though. You can't make the change without breaking all the code that calls your constructor with new. You can't switch to using object pools for performance gains, for instance.

Also, using constructors gives you a deceptive instanceof that doesn't work across execution contexts, and doesn't work if your constructor prototype gets swapped out. It will also fail if you start out returning this from your constructor, and then switch to exporting an arbitrary object, which you'd have to do to enable factory-like behavior in your constructor.

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. Factories can also instantiate objects across execution contexts, take advantage of object pools, and allow for more flexible prototypal inheritance models.

  • 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).

Eric Elliott
  • 4,387
  • 1
  • 23
  • 33
  • 2
    In what sense do you mean that constructors make the callers tightly coupled to their implementation? As far the constructor arguments are concerned, those will need to be passed even to the factory function for it to use them and invoke the appropriate constructor within. – Bharat Khatri Mar 05 '14 at 15:00
  • In the sense that callers must use `new` for constructors, but can't use `new` for factories. See the new Open/Closed principle section in my answer for more detail. – Eric Elliott Mar 06 '14 at 17:50
  • 4
    Regarding the violation of Open/Closed: isn't this all about dependency injection? If A needs B, wether A calls new B() or A call BFactory.create(), both of them introduce coupling. If on the other hand you give A an instance of B in the composition root, A doesn't need to know anything at all about how B is instantiated. I feel both constructors and factories have their uses; constructors are for simple instantiation, factories for more complex instantiation. But in both cases, injecting your dependencies is wise. – Stefan Billiet Mar 18 '14 at 10:51
  • @StefanBilliet There's more to it than that. See my comment about object pools. If you start with `new` and switch to object pools, any code relying on `new` and `instanceof` will break, because your pooled objects will no longer be instances of the constructor prototype unless you manually wire it up. If that pool lives in a different execution context, forget about it. Can't be done... – Eric Elliott Mar 18 '14 at 16:58
  • @StefanBilliet I think I initially missed your point about dependency injection, so let me take another swing: It sounds like you're suggesting that every time you see something that requires `new`, you wrap it with an instantiator factory, and only call that factory, instead of calling the constructor directly. This would introduce too much abstraction. If you start with factories, it's factories all the way down. No need for extra wrappers and unnecessary DI frameworks. – Eric Elliott Mar 18 '14 at 17:05
  • 1
    DI is good for injecting state: configuration, domain objects, and so on. It's overkill for everything else. – Eric Elliott Mar 18 '14 at 17:14
  • I write Javascript all day long and whenever I forget "new", JSHint just tells me about it, I fix it and I move on. What's all the fuss about? Every JS library author is not going to follow this advice, so you're going to have to deal with it anyway. Look Google is making you use "new" if you want to use their Maps API client - https://developers.google.com/maps/documentation/javascript/tutorial#HelloWorld – Wayne Bloss Nov 07 '14 at 20:26
  • 1
    The fuss is that requiring `new` violates the open / closed principle. See https://medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3 for a much bigger discussion than these comments allow. – Eric Elliott Nov 08 '14 at 02:05
  • 1
    @EricElliott , I ran into you when my use of `new` (because I thought I should?) blew a privacy hole in my code. I've gained a deeper understanding through your postings/blogs, which essentially confirmed my approach and put a name to it. I resist Stampit because I view it as a layer of abstraction which - essentially - teaches the homeless dependency on you, the advocate. Can you link a solution to my angst and make me a disciple? In the interim, 'thanks' for your work. (I hate Adobe less now.) – Ricalsin Mar 18 '15 at 17:02
  • @Ricalsin The most popular prototype-based object creation solutions are the ones that got added to the ES spec: `Object.create()` and `Object.assign()`, either of which can be used to instantiate and initialize objects in any function. AFAIK, Stampit is the most popular solution that allows you to compose factories. – Eric Elliott Apr 12 '15 at 22:39
  • If one were to use a Factory Function (FF) like this (probably worth viewing in a text editor): `function FF(constructorArg) { var _privateName = constructorArg; var publicMessage = "Hello StackOverflow"; function publicMethodGetName() { return _privateName; } return { publicMethodGetName: publicMethodGetName, publicMessage: publicMessage }; }` and was sure that they would NEVER use the 'this' keyword inside the FF, would it then be acceptable to do var ff = new FF()? That way you get the readability of using 'new' and don't need to worry about the problems with the 'this' keyword. – user5508297 Aug 21 '16 at 03:08
  • 3
    Because any function can return a new object in JavaScript, and quite a lot of them do so without the `new` keyword, I don't believe that the `new` keyword actually does provide any additional readability. IMO, it seems silly to jump through hoops in order to enable callers to type more. – Eric Elliott Aug 27 '16 at 23:15
  • @EricElliott _"If you start with new and switch to object pools, any code relying on new and instanceof will break"_. I wonder how utilizing a factory function helps consumer `instanceof`-depending code to not break. Would appreciate if you could elaborate more. – sepehr Jan 17 '20 at 23:03
  • Code relying on a constructor will often break if you switch to a factory. 1. Factories don't hook up the prototype link by default, meaning `instanceof` will fail for factory-produced instances (unless you manually wire them up in the factory). That broken connection is a good thing though because instanceof lies. Better to always fail than only sometimes work. 2. `this` inside the factory will not refer to the newly created instance. 3. Arrow function factories also throw if you call them with `new`. – Eric Elliott Jan 18 '20 at 10:51
  • only argument I could understand was people forgetting to add new, which is not a problem anymore with es6 – Code Name Jack Jun 04 '20 at 11:34
  • 1
    @CodeNameJack Constructors CAN'T be used to create working object pools because the point of an object pool is to avoid garbage collection by recycling pre-instantiated objects instead of creating new ones. But the first thing the `new` keyword does is instantiate an object and bind `this` to it. Constructors SHOULDN'T be used for abstract factories which wire up alternate prototypes because that violates caller assumptions that instance.__proto__ will be wired to Constructor.prototype (enabling instanceof, etc.). – Eric Elliott Jun 15 '20 at 01:14
  • Object pool is a solid example, but Abstract factory can continue to use constructors internally, as using same instance is not a mandatory or not even a common case with Abstract factory. Or did I understand it wrong? – Code Name Jack Jun 15 '20 at 06:31
  • @CodeNameJack Abstract factories using `new` are awkward because callers invoking things with the `new` keyword expect the `Constructor.prototype` to be in the prototype chain of the new instance. Often, you'll want your instances to have a different prototype depending on the type the abstract factory selects for it, not the `Constructor.prototype`. Using `new` internally is fine, but callers are already using `new`, which is why it's a breaking change to start with a constructor and move to abstract factory. – Eric Elliott Jun 23 '20 at 23:57
40

A constructor returns an instance of the class you call it on. A factory function can return anything. You would use a factory function when you need to return arbitrary values or when a class has a large setup process.

Ignacio Vazquez-Abrams
  • 699,552
  • 132
  • 1,235
  • 1,283
8

A Constructor function example

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");
  • new creates an object prototyped on User.prototype and calls User with the created object as its this value.

  • new treats an argument expression for its operand as optional:

         let user = new User;
    

    would cause new to call User with no arguments.

  • new returns the object it created, unless the constructor returns an object value, which is returned instead. This is an edge case which for the most part can be ignored.

Pros and Cons

Objects created by constructor functions inherit properties from the constructor's prototype property, and return true using the instanceOf operator on the constructor function.

The above behaviors can fail if you dynamically change the value of the constructor's prototype property after having already used the constructor. Doing so is rare, and it can't be changed if the constructor were created using the class keyword.

Constructor functions can be extended using the extends keyword.

Constructor functions can't return null as an error value. Since it's not an object data type, it is ignored by new.

A Factory function example

function User(name, age) {
  return {
    name,
    age,
  }
};

let user = User("Tom", 23);

Here the factory function is called without new. The function is entirely responsible for the direct or indirect use if its arguments and the type of object it returns. In this example it returns a simple [Object object] with some properties set from arguments.

Pros and Cons

Easily hides the implementation complexities of object creation from the caller. This is particularly useful for native code functions in a browser.

The factory function need not always return objects of the same type, and could even return null as an error indicator.

In simple cases, factory functions can be simple in structure and meaning.

Objects returned do not generally inherit from the factory function's prototype property, and return false from instanceOf factoryFunction.

The factory function can't be safely extended using the extends keyword because extended objects would inherit from the factory functions prototype property instead of from the prototype property of the constructor used by the factory function.

Community
  • 1
  • 1
traktor
  • 12,838
  • 3
  • 23
  • 44
  • 1
    This is a late answer posted in response to [this question](https://stackoverflow.com/q/53927063/5217142) on the same subject, – traktor Dec 26 '18 at 05:15
  • not just "null" but the "new" will also ignore any premitive datatype returned by the contructor function. – Vishal Jun 03 '20 at 11:51
3

Factories are "always" better. When using object orientated languages then

  1. decide on the contract (the methods and what they will do)
  2. Create interfaces that expose those methods (in javascript you don't have interfaces so you need to come up with some way of checking the implementation)
  3. Create a factory that returns an implementation of each interface required.

The implementations (the actual objects created with new) are not exposed to the factory user/consumer. This means that the factory developer can expand and create new implementations as long as he/she doesn't break the contract...and it allows for the factory consumer to just benefit from the new API without having to change their code...if they used new and a "new" implementation comes along then they have to go and change every line which uses "new" to use the "new" implementation...with the factory their code doesn't change...

Factories - better than all anything else - the spring framework is completely built around this idea.

0

Factories are a layer of abstraction, and like all abstractions they have a.cost in complexity. When encountering a factory based API figuring out what the factory is for a given API can be challenging for the API consumer. With constructors discoverability is trivial.

When deciding between ctors and factories you need to decide if the complexity is justified by the benefit.

Worth noting that Javascript constructors can be arbitrary factories by returning something other than this or undefined. So in js you can get the best of both worlds - discoverable API and object pooling/caching.

PeterH
  • 161
  • 1
  • 5
  • 5
    In JavaScript, the cost of using constructors is higher than the cost of using factories because any function in JS can return a new object. Constructors add complexity by: Requiring `new`, Altering behavior of `this`, Altering return value, Connecting a prototype ref, Enabling `instanceof` (which lies and should not be used for this purpose). Ostensibly, all of those are "features". In practice, they hurt your code quality. – Eric Elliott Jun 17 '15 at 19:49
0

For the differences, Eric Elliott clarified very well,

But for the second question:

When to use one instead of the other?

If you are coming from the object-oriented background, Constructor function looks more natural to you. this way you shouldn't forget to use new keyword.

Mostafa
  • 2,577
  • 8
  • 42
  • 70
0

one new thing to add for previous answers is that there is a new way to declare Constructor functions.

class CreateCirle {
    constructor(radius) {
        this.radius = radius;
        this.draw = function () {
            console.log('we draw a circle with radius: ', this.radius);
        };
        this.name = "Circly";
        this.address = "Math Graph";
    }
}

you have to add class and constructor keyword.

then invoke it normally with no difference.

let cirle = new CreateCirle(5);
cirle.draw();

Don't forget to make it with PascalCase name convention as mentioned before.