Hi, from my limited understanding of both concepts there are two big differences between the two. Firstly, constructors create a prototype and factory functions don't. Secondly, factory functions return an object(which can include functions). so if we return functions that reference variables we don't want a user to directly access we effectively create a private variable(using closure). However I just discovered that constructors can have private variables by defining variables without the "this" keyword. So my question is as follows: Why would someone choose factory functions over constructors? I can't see a valid reason for wanting to avoid prototypal inheritance since it can provide extra behaviour when needed and constructors can implement private variables as well.
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.
Benefits of using constructors
Most books teach you to use constructors and
newthisrefers to the new objectSome people like the way
var myFoo = new Foo();reads.
Drawbacks
Details of instantiation get leaked into the calling API (via the
newrequirement), 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
newis 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 forgetnewwith aclassconstructor, or the constructor will throw an error.If you do the
instanceofcheck, it leaves ambiguity as to whether or notnewis required. In my opinion, it shouldn't be. You've effectively short circuited thenewrequirement, 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 flexiblethiscontext.
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 makethisbehave badly, see next point).thisbehaves as it normally would - so you can use it to access the parent object (for example, insideplayer.create(),thisrefers toplayer, just like any other method invocation would.callandapplyalso reassignthis, 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();orvar myFoo = foo.create();reads.
Drawbacks
newdoesn't behave as expected (see above). Solution: don't use it.thisdoesn't refer to the new object (instead, if the constructor is invoked with dot notation or square bracket notation, e.g. foo.bar() -thisrefers tofoo- just like every other JavaScript method -- see benefits).
Can anyone explain me what's the difference between factory functions and constructors?
I'm at THIS LESSON from The Odin Project and after reading it a bunch of times, I still can't understand the difference. I watched a couple of videos on the matter but I can wrap my head around it.
I understand that with a constructor you new to use the keyword new to create an instance of the object:
function Player(name, marker) {
this.name = name
this.marker = marker
}
const player = new Player('steve', 'X')And with the factory function you return a new object:
const playerFactory = (name, marker) => {
return { name, marker }
}
const player = playerFactory('steve', 'X')Soooo, that's the only difference that I found. Am I stupid or what? Please help.
note: english it's not my first language. In case I made a spelling mistake.
Is there any practical reason why I would create a class or constructor over a factory function?
I've started JavaScript a few months ago and it's great how there are many different ways to create an object but, at times, all the different methods can be confusing. The more I research, the more it appears too that the other methods seem to be obsolete compared to Factory Functions.
Here's what I got until now..
Both ways are done to create a "blueprint" for numerous objects that share some functionality..
The factory function returns a new object, also easier to encapsulate things by simply not returning them but by using closure they can still be accessed from inside the function..
With constructors you need to use the "new" keyword in the object instantiation, behind the scenes the function creates an object called "this" and returns it with the code you wrote.
In the course I'm doing (The Odin Project), they advise using factory functions over constructors.. Also instead of using inheritance, to use composition.. Which for me is great, because out of all of these, factory functions + composition is what I understood the most..
Constructors, "this" keyword, prototypes and all that still kind of confuse me..
I wrote this little code to try and see if I could do something with factory functions and compositions.. Did I do it right or could have it have been better?
https://jsfiddle.net/va35kyrd/
https://codesandbox.io/s/muddy-fast-nc2nfl?file=/src/index.js
The idea is that player1(p1) has power of flight, p2 has power of invisibility.. Both can attack and heal, and then p3 is overpowered so he has both powers and more health and healing ability..
I feel like I messed up with p3, passing in the if statement in line 17 could get messy with lots of different players.. If I set p3 health and healing when I create it, it still uses the default ones of 5 and 3 (line 14).
tl;dr: help me understand which inheritance pattern is 'best' (in which situation)
I've read Douglas Crockford's "The Good Parts" and I'm working my way through Haverbeke's "Elequent Javascript." These books take a different approach towards inheritance with Crockford recommending the use of 'factory functions' to perform inheritance and discouraging 'psuedoclassical' or constructor based inheritance. (A quick example for clarity)
// factory function (assume a mammal() factory function exists elsewhere)
var cat = function(name,){
var that = object.Create(mammal(name));
that.says = function() { console.log('my name is ' + this.name ) };
return that;
};
var garfield = cat('garfield');vs
// psuedoclassical (assume a Mammal() constructor exists elsewhere)
var Cat = function(name){
this.name = name;
};
Cat.prototype = new Mammal( );
Cat.prototype.says = function() { console.log('my name is ' + this.name ) };
var heathcliff = new Cat('heathcliff');Can you guys weigh in on the pros/cons and any personal preference you may have for either of these mechanisms? Crockford comes out pretty strongly on the former method but he seems to be the only one that pushes it. Not to mention that ES6 appears to introduce keywords to further commit to the psuedoclassical model, though much of the comments surrounding that functionality state that this is all just masking the 'true nature' of javascript (ie: prototypes, not classes).
The best that I can figure the actual functional difference between these two mechanisms are:
-
In the factory function pattern you don't end up with a prototype that can (easily) be used to modify all instances of the child class. Because an object, not a constructor function, is the prototype you must maintain that object if you want to affect all children. In the example above this is not possible because I wrote it to call 'mammal(name)' which would give us a different instance every time.
-
In the factory function pattern some of the new functionality which allows you to control the types of the properties that you add (for example to prevent them from being enumerated or to create get/set functions) is unavailable.
Sorry for the wall of text... I could take this to stackoverflow but I figured I'd start here.