TL;DR:
Do we need factories/constructors in prototypical OO? Can we make a paradigm switch and drop them completely?
The BackStory:<
The short answer to your question "Do we need factories/constructors in prototypical OO?" is no. Factories/Constructors serve 1 purpose only: initialize the newly created object (an instance) to a specific state.
That being said, it is often uses because some objects need initialization code of some sort.
Let's use the component-based entity code you provided. A typical entity is simply a collection of components and few properties:
var BaseEntity = Object.create({},
{
/* Collection of all the Entity's components */
components:
{
value: {}
}
/* Unique identifier for the entity instance */
, id:
{
value: new Date().getTime()
, configurable: false
, enumerable: true
, writable: false
}
/* Use for debugging */
, createdTime:
{
value: new Date()
, configurable: false
, enumerable: true
, writable: false
}
, removeComponent:
{
value: function() { /* code left out for brevity */ }
, enumerable: true
, writable: false
}
, addComponent:
{
value: function() { /* code left out for brevity */ }
, enumerable: true
, writable: false
}
});
Now the following code will create new entities based on the 'BaseEntity'
function CreateEntity()
{
var obj = Object.create(BaseEntity);
//Output the resulting object's information for debugging
console.log("[" + obj.id + "] " + obj.createdTime + "\n");
return obj;
}
Seems straight forward enough, until you go to reference the properties:
setTimeout(CreateEntity, 1000);
setTimeout(CreateEntity, 2000);
setTimeout(CreateEntity, 3000);
outputs:
[1309449384033] Thu Jun 30 2011 11:56:24 GMT-0400 (EDT)
[1309449384033] Thu Jun 30 2011 11:56:24 GMT-0400 (EDT)
[1309449384033] Thu Jun 30 2011 11:56:24 GMT-0400 (EDT)
So why is this? The answer is simple: because of prototype based inheritance. When we created the objects, there wasn't any code to set the properties id and createdTime on the actual instance, as is normally done in constructors/factories. As a result, when the property is accessed, it pulls from the prototype chain, which ends up being a single value for all entities.
The argument to this is that the Object.create() should be passed the second parameter to set this values. My response would simply be: Isn't that basically the same as calling a constructor or using a factory? It's just another way of setting an object's state.
Now with your implementation where you treat (and rightfully so) all prototypes as a collection of static methods and properties, you do initialize the object by assigning the values of the properties to the data from a data source. It may not be using new or some type of factory, but it is initialization code.
To summarize:
In JavaScript prototype OOP
- new is not needed
- Factories are not needed
- Initialization code is usually needed, which is normally done through new, factories, or some other implementation that you don't want to admit is initializing an object