How to write JavaScript with factory functions
Basically I would distinguish 3 approaches to create an object in JS:
- Class
- Constructor
- Factory
Here are 3 examples (considering your Rabbit's one)
// class
class Rabbit {
constructor() {
this.speed = 3;
// it would be so nice to have just 'static const speed = 3;' instead of
// using constructor for that
}
getSpeed() {
return this.speed;
}
}
let rabbit1 = new Rabbit();
// constructor
function ConstructorRabbit(){ }
ConstructorRabbit.prototype.speed = 3;
ConstructorRabbit.prototype.getSpeed = function() {
return this.speed;
};
let rabbit2 = new ConstructorRabbit();
// factory
const rabbitProto = {
speed: 3,
getSpeed() {
return this.speed;
}
};
function factoryRabbit () {
return Object.create(rabbitProto);
}
let rabbit3 = factoryRabbit();
I'm not sure that there are so many pros to use only factory for creating objects, but probably I can single out the one. As mentioned in the article if we refer to very famous 'Design Patterns', so we should prefer object composition instead of class inheritance. And I'm totally agree with that postulate, thus returning back to JS and ES6 classes, we can say that prototype delegation may be better than class inheritance in some cases.
But also, we shouldn't forget this (as mentioned in the article as well) statement: "How it’s implemented doesn’t matter at all unless it’s implemented poorly". And this one, I would say, is a really good one.
Many answers here suggest Constructor Functions, although the name of the questions has to do with Factory Functions.
Factory Functions look like the following:
const RabbitFactory = () => {
const speed = 3;
const GetSpeed = () => speed;
return { GetSpeed }
}
const rabbit = RabbitFactory();
rabbit.GetSpeed() // -> 3
rabbit.speed // -> undefined!
I like Factory functions more than Constructor function because:
- You don't need to get messy with prototyping
- You don't need to use the
Object
constructor - Gives you the ability to choose what is private and what is public in your factory
(in my example, speed is private and this is a good practice. If you want to read the value of rabbit's speed, use theGetSpeed
getter)
No, that is wrong. You should not use Object.setPrototypeOf
, better use Object.create
(though it makes no difference for the result). And if you create the prototype from an object literal every time, it loses all of its sharing advantages, so you should either drop that completely or move it outside the function to make it static. The correct™ way to write the factory function would be
const protoRabbit = {
getSpeed: function() {
return this.speed;
}
};
function createRabbit() {
var rabbit = Object.create(protoRabbit);
rabbit.speed = 3;
return rabbit;
}
var rabbit = createRabbit();