TL;DR:
Do we need factories/constructors in prototypical OO? Can we make a paradigm switch and drop them completely?
The BackStory:
I’ve been toying with doing prototypical OO in JavaScript lately and find that 99% of OO done in JavaScript is forcing classical OO patterns into it.
My take on prototypical OO is that it involves two things. A static prototype of methods (and static data) and a data binding. We don’t need factories or constructors.
In JavaScript these are Object literals containing functions and Object.create.
This would mean we can model everything as a static blueprint/prototype and a data binding abstraction that’s preferably hooked straight into a document-style database. I.e. objects are taken out of the database and created by cloning a prototype with the data. This would mean there is no constructor logic, no factories, no new.
The Example code:
An pseudo example would be :
var Entity = Object.create(EventEmitter, {
addComponent: {
value: function _addComponent(component) {
if (this[component.type] !== undefined) {
this.removeComponent(this[component.type]);
}
_.each(_.functions(component), (function _bind(f) {
component[f] = component[f].bind(this);
}).bind(this));
component.bindEvents();
Object.defineProperty(this, component.type, {
value: component,
configurable: true
});
this.emit("component:add", this, component);
}
},
removeComponent: {
value: function _removeComponent(component) {
component = component.type || component;
delete this[component];
this.emit("component:remove", this, component);
}
}
}
var entity = Object.create(Entity, toProperties(jsonStore.get(id)))
The minor explanation:
The particular code is verbose because ES5 is verbose. Entity above is a blueprint/prototype. Any actual object with data would be created by using Object.create(Entity, {...}).
The actual data (in this case the components) is directly loaded from a JSON store and injected directly into the Object.create call. Of course a similar pattern is applied to creating components and only properties that pass Object.hasOwnProperty are stored in the database.
When an entity is created for the first time it’s created with an empty {}
The actual Questions:
Now my actual questions are
- Open source examples of JS prototypical OO?
- Is this a good idea?
- Is it in-line with the ideas and concepts behind prototypical OOP?
- Will not using any constructors/factory functions bite me in the ass somewhere? Can we really get away with not using constructors. Are there any limitations using the above methodology where we would need factories to overcome them.
As per your comment that the question is mainly “is constructor knowledge necessary?” I feel it is.
A toy example would be storing partial data. On a given data set in memory, when persisting I may only choose to store certain elements (either for the sake of efficiency or for data consistency purposes, e.g. the values are inherently useless once persisted). Let’s take a session where I store the user name and the number of times they’ve clicked on the help button (for lack of a better example). When I persist this in my example, I do have no use for the number of clicks, since I keep it in memory now, and next time I load the data (next time the user logs in or connects or whatever) I will initialise the value from scratch (presumably to 0). This particular use case is a good candidate for constructor logic.
Aahh, but you could always just embed that in the static prototype:
Object.create({name:'Bob', clicks:0});Sure, in this case. But what if the value wasn’t always 0 at first, but rather it was something that required computation. Uummmm, say, the users age in seconds (assuming we stored the name and the DOB). Again, an item that there is little use persisting, since it will need to be recalculated on retrieval anyway. So how do you store the user’s age in the static prototype?The obvious answer is constructor/initialiser logic.
There are many more scenarios, although I don’t feel the idea is much related to js oop or any language in particular. The necessity for entity creation logic is inherent in the way I see computer systems model the world. Sometimes the items we store will be a simple retrieval and injection into a blueprint like prototype shell, and sometimes the values are dynamic, and will need to be initialised.
UPDATE
OK, I’m going to try for a more real-world example, and to avoid confusion assume that I have no database and need not persist any data. Let’s say I’m making a solitaire server. Each new game will be (naturally) a new instance of the
Gameprototype. It is clear to me that their is initialiser logic required here (and lots of it):I will, for example, need on each game instance not just a static/hard-coded deck of cards, but a randomly shuffled deck. If it were static the user would play the same game every time, which is clearly not good.
I may also have to start a timer to finish the game if the player runs out. Again, not something that can be static, since my game has a few requirements: the number of seconds is inversely related to the number of games the connected player has won so far (again, no saved info, just how many for this connection), and proportional to the difficulty of the shuffle (there is an algorithm that according to the shuffle results can determine the degree of difficulty of the game).
How do you do that with a static
Object.create()?